home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / util4 / bytmrk20.lha / nbench1.c < prev    next >
C/C++ Source or Header  |  1995-11-03  |  117KB  |  4,289 lines

  1.  
  2. /*
  3. ** nbench1.c
  4. */
  5.  
  6. /********************************
  7. **       BYTEmark (tm)         **
  8. ** BYTE NATIVE MODE BENCHMARKS **
  9. **       VERSION 2             **
  10. **                             **
  11. ** Included in this source     **
  12. ** file:                       **
  13. **  Numeric Heapsort           **
  14. **  String Heapsort            **
  15. **  Bitfield test              **
  16. **  Floating point emulation   **
  17. **  Fourier coefficients       **
  18. **  Assignment algorithm       **
  19. **  IDEA Encyption             **
  20. **  Huffman compression        **
  21. **  Back prop. neural net      **
  22. **  LU Decomposition           **
  23. **    (linear equations)       **
  24. ** ----------                  **
  25. ** Rick Grehan, BYTE Magazine  **
  26. *********************************
  27. */
  28.  
  29. /*
  30. ** INCLUDES
  31. */
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <math.h>
  36. #include "nmglobal.h"
  37. #include "nbench1.h"
  38. #include "sysspec.h"
  39. #include "wordcat.h"
  40.  
  41.  
  42. #ifndef MAC
  43. #include <mem.h>
  44. #endif
  45. /*********************
  46. ** NUMERIC HEAPSORT **
  47. **********************
  48. ** This test implements a heapsort algorithm, performed on an
  49. ** array of longs.
  50. */
  51.  
  52. /**************
  53. ** DoNumSort **
  54. ***************
  55. ** This routine performs the CPU numeric sort test.
  56. ** NOTE: Last version incorrectly stated that the routine
  57. **  returned result in # of longword sorted per second.
  58. **  Not so; the routine returns # of iterations per sec.
  59. */
  60.  
  61. void DoNumSort(void)
  62. {
  63. SortStruct *numsortstruct;      /* Local pointer to global struct */
  64. farlong *arraybase;     /* Base pointers of array */
  65. long accumtime;         /* Accumulated time */
  66. double iterations;      /* Iteration counter */
  67. char *errorcontext;     /* Error context string pointer */
  68. int systemerror;        /* For holding error codes */
  69.  
  70. /*
  71. ** Link to global structure
  72. */
  73. numsortstruct=&global_numsortstruct;
  74.  
  75. /*
  76. ** Set the error context string.
  77. */
  78. errorcontext="CPU:Numeric Sort";
  79.  
  80. /*
  81. ** See if we need to do self adjustment code.
  82. */
  83. if(numsortstruct->adjust==0)
  84. {
  85.         /*
  86.         ** Self-adjustment code.  The system begins by sorting 1
  87.         ** array.  If it does that in no time, then two arrays
  88.         ** are built and sorted.  This process continues until
  89.         ** enough arrays are built to handle the tolerance.
  90.         */
  91.         numsortstruct->numarrays=1;
  92.         while(1)
  93.         {
  94.                 /*
  95.                 ** Allocate space for arrays
  96.                 */
  97.                 arraybase=(farlong *)AllocateMemory(sizeof(long) *
  98.                         numsortstruct->numarrays * numsortstruct->arraysize,
  99.                         &systemerror);
  100.                 if(systemerror)
  101.                 {       ReportError(errorcontext,systemerror);
  102.                         FreeMemory((farvoid *)arraybase,
  103.                                   &systemerror);
  104.                         ErrorExit();
  105.                 }
  106.  
  107.                 /*
  108.                 ** Do an iteration of the numeric sort.  If the
  109.                 ** elapsed time is less than or equal to the permitted
  110.                 ** minimum, then allocate for more arrays and
  111.                 ** try again.
  112.                 */
  113.                 if(DoNumSortIteration(arraybase,
  114.                         numsortstruct->arraysize,
  115.                         numsortstruct->numarrays)>global_min_ticks)
  116.                         break;          /* We're ok...exit */
  117.  
  118.                 FreeMemory((farvoid *)arraybase,&systemerror);
  119.                 if(numsortstruct->numarrays++>NUMNUMARRAYS)
  120.                 {       printf("CPU:NSORT -- NUMNUMARRAYS hit.\n");
  121.                         ErrorExit();
  122.                 }
  123.         }
  124. }
  125. else
  126. {       /*
  127.         ** Allocate space for arrays
  128.         */
  129.         arraybase=(farlong *)AllocateMemory(sizeof(long) *
  130.                 numsortstruct->numarrays * numsortstruct->arraysize,
  131.                 &systemerror);
  132.         if(systemerror)
  133.         {       ReportError(errorcontext,systemerror);
  134.                 FreeMemory((farvoid *)arraybase,
  135.                           &systemerror);
  136.                 ErrorExit();
  137.         }
  138.  
  139. }
  140. /*
  141. ** All's well if we get here.  Repeatedly perform sorts until the
  142. ** accumulated elapsed time is greater than # of seconds requested.
  143. */
  144. accumtime=0L;
  145. iterations=(double)0.0;
  146.  
  147. do {
  148.         accumtime+=DoNumSortIteration(arraybase,
  149.                 numsortstruct->arraysize,
  150.                 numsortstruct->numarrays);
  151.         iterations+=(double)1.0;
  152. } while(TicksToSecs(accumtime)<numsortstruct->request_secs);
  153.  
  154. /*
  155. ** Clean up, calculate results, and go home.  Be sure to
  156. ** show that we don't have to rerun adjustment code.
  157. */
  158. FreeMemory((farvoid *)arraybase,&systemerror);
  159.  
  160. numsortstruct->sortspersec=iterations * 
  161.         (double)numsortstruct->numarrays / TicksToFracSecs(accumtime);
  162.  
  163. if(numsortstruct->adjust==0)
  164.         numsortstruct->adjust=1;
  165.  
  166. return;
  167. }
  168.  
  169. /***********************
  170. ** DoNumSortIteration **
  171. ************************
  172. ** This routine executes one iteration of the numeric
  173. ** sort benchmark.  It returns the number of ticks
  174. ** elapsed for the iteration.
  175. */
  176. static ulong DoNumSortIteration(farlong *arraybase,
  177.                 ulong arraysize,
  178.                 uint numarrays)
  179. {
  180. ulong elapsed;          /* Elapsed ticks */
  181. ulong i;
  182. /*
  183. ** Load up the array with random numbers
  184. */
  185. LoadNumArrayWithRand(arraybase,arraysize,numarrays);
  186.  
  187. /*
  188. ** Start the stopwatch
  189. */
  190. elapsed=StartStopwatch();
  191.  
  192. /*
  193. ** Execute a heap of heapsorts
  194. */
  195. for(i=0;i<numarrays;i++)
  196.         NumHeapSort(arraybase+i*arraysize,0L,arraysize-1L);
  197.  
  198. /*
  199. ** Get elapsed time
  200. */
  201. elapsed=StopStopwatch(elapsed);
  202. #ifdef DEBUG
  203. {
  204.  
  205.         for(i=0;i<arraysize-1;i++)
  206.         {       /*
  207.                 ** Compare to check for proper
  208.                 ** sort.
  209.                 */
  210.                 if(arraybase[i+1]<arraybase[i])
  211.                 {       printf("Sort Error\n");
  212.                         break;
  213.                 }
  214.         }
  215. }
  216. #endif
  217.  
  218. return(elapsed);
  219. }
  220.  
  221. /*************************
  222. ** LoadNumArrayWithRand **
  223. **************************
  224. ** Load up an array with random longs.
  225. */
  226. static void LoadNumArrayWithRand(farlong *array,     /* Pointer to arrays */
  227.                 ulong arraysize,
  228.                 uint numarrays)         /* # of elements in array */
  229. {
  230. long i;                 /* Used for index */
  231. farlong *darray;        /* Destination array pointer */
  232. /*
  233. ** Initialize the random number generator
  234. */
  235. randnum(13L);
  236.  
  237. /*
  238. ** Load up first array with randoms
  239. */
  240. for(i=0L;i<arraysize;i++)
  241.         array[i]=randnum(0L);
  242.  
  243. /*
  244. ** Now, if there's more than one array to load, copy the
  245. ** first into each of the others.
  246. */
  247. darray=array;
  248. while(--numarrays)
  249. {       darray+=arraysize;
  250.         for(i=0L;i<arraysize;i++)
  251.                 darray[i]=array[i];
  252. }
  253.         
  254. return;
  255. }
  256.  
  257. /****************
  258. ** NumHeapSort **
  259. *****************
  260. ** Pass this routine a pointer to an array of long
  261. ** integers.  Also pass in minimum and maximum offsets.
  262. ** This routine performs a heap sort on that array.
  263. */
  264. static void NumHeapSort(farlong *array,
  265.         ulong bottom,           /* Lower bound */
  266.         ulong top)              /* Upper bound */
  267. {
  268. ulong temp;                     /* Used to exchange elements */
  269. ulong i;                        /* Loop index */
  270.  
  271. /*
  272. ** First, build a heap in the array
  273. */
  274. for(i=(top/2L); i>0; --i)
  275.         NumSift(array,i,top);
  276.  
  277. /*
  278. ** Repeatedly extract maximum from heap and place it at the
  279. ** end of the array.  When we get done, we'll have a sorted
  280. ** array.
  281. */
  282. for(i=top; i>0; --i)
  283. {       NumSift(array,bottom,i);
  284.         temp=*array;                    /* Perform exchange */
  285.         *array=*(array+i);
  286.         *(array+i)=temp;
  287. }
  288. return;
  289. }
  290.  
  291. /************
  292. ** NumSift **
  293. *************
  294. ** Peforms the sift operation on a numeric array,
  295. ** constructing a heap in the array.
  296. */
  297. static void NumSift(farlong *array,     /* Array of numbers */
  298.         ulong i,                /* Minimum of array */
  299.         ulong j)                /* Maximum of array */
  300. {
  301. unsigned long k;
  302. long temp;                              /* Used for exchange */
  303.  
  304. while((i+i)<=j)
  305. {
  306.         k=i+i;
  307.         if(k<j)
  308.                 if(array[k]<array[k+1L])
  309.                         ++k;
  310.         if(array[i]<array[k])
  311.         {
  312.                 temp=array[k];
  313.                 array[k]=array[i];
  314.                 array[i]=temp;
  315.                 i=k;
  316.         }
  317.         else
  318.                 i=j+1;
  319. }
  320. return;
  321. }
  322.  
  323. /********************
  324. ** STRING HEAPSORT **
  325. ********************/
  326.  
  327. /*****************
  328. ** DoStringSort **
  329. ******************
  330. ** This routine performs the CPU string sort test.
  331. ** Arguments:
  332. **      requested_secs = # of seconds to execute test
  333. **      stringspersec = # of strings per second sorted (RETURNED)
  334. */
  335. void DoStringSort(void)
  336. {
  337.  
  338. SortStruct *strsortstruct;      /* Local for sort structure */
  339. faruchar *arraybase;            /* Base pointer of char array */
  340. long accumtime;                 /* Accumulated time */
  341. double iterations;              /* # of iterations */
  342. char *errorcontext;             /* Error context string pointer */
  343. int systemerror;                /* For holding error code */
  344.  
  345. /*
  346. ** Link to global structure
  347. */
  348. strsortstruct=&global_strsortstruct;
  349.  
  350. /*
  351. ** Set the error context
  352. */
  353. errorcontext="CPU:String Sort";
  354.  
  355. /*
  356. ** See if we have to perform self-adjustment code
  357. */
  358. if(strsortstruct->adjust==0)
  359. {
  360.         /*
  361.         ** Initialize the number of arrays.
  362.         */
  363.         strsortstruct->numarrays=1;
  364.         while(1)
  365.         {
  366.                 /*
  367.                 ** Allocate space for array.  We'll add an extra 100
  368.                 ** bytes to protect memory as strings move around
  369.                 ** (this can happen during string adjustment)
  370.                 */
  371.                 arraybase=(faruchar *)AllocateMemory((strsortstruct->arraysize+100L) *
  372.                         (long)strsortstruct->numarrays,&systemerror);
  373.                 if(systemerror)
  374.                 {       ReportError(errorcontext,systemerror);
  375.                         ErrorExit();
  376.                 }
  377.  
  378.                 /*
  379.                 ** Do an iteration of the string sort.  If the
  380.                 ** elapsed time is less than or equal to the permitted
  381.                 ** minimum, then de-allocate the array, reallocate a
  382.                 ** an additional array, and try again.
  383.                 */
  384.                 if(DoStringSortIteration(arraybase,
  385.                         strsortstruct->numarrays,
  386.                         strsortstruct->arraysize)>global_min_ticks)
  387.                         break;          /* We're ok...exit */
  388.  
  389.                 FreeMemory((farvoid *)arraybase,&systemerror);
  390.                 strsortstruct->numarrays+=1;
  391.         }
  392. }
  393. else
  394. {
  395.         /*
  396.         ** We don't have to perform self adjustment code.
  397.         ** Simply allocate the space for the array.
  398.         */
  399.         arraybase=(faruchar *)AllocateMemory((strsortstruct->arraysize+100L) *
  400.                 (long)strsortstruct->numarrays,&systemerror);
  401.         if(systemerror)
  402.         {       ReportError(errorcontext,systemerror);
  403.                 ErrorExit();
  404.         }
  405. }
  406. /*
  407. ** All's well if we get here.  Repeatedly perform sorts until the
  408. ** accumulated elapsed time is greater than # of seconds requested.
  409. */
  410. accumtime=0L;
  411. iterations=(double)0.0;
  412.  
  413. do {
  414.         accumtime+=DoStringSortIteration(arraybase,
  415.                                 strsortstruct->numarrays,
  416.                                 strsortstruct->arraysize);
  417.         iterations+=(double)strsortstruct->numarrays;
  418. } while(TicksToSecs(accumtime)<strsortstruct->request_secs);
  419.  
  420. /*
  421. ** Clean up, calculate results, and go home.
  422. ** Set flag to show we don't need to rerun adjustment code.
  423. */
  424. FreeMemory((farvoid *)arraybase,&systemerror);
  425. strsortstruct->sortspersec=iterations / (double)TicksToFracSecs(accumtime);
  426. if(strsortstruct->adjust==0)
  427.         strsortstruct->adjust=1;
  428. return;
  429. }
  430.  
  431. /**************************
  432. ** DoStringSortIteration **
  433. ***************************
  434. ** This routine executes one iteration of the string
  435. ** sort benchmark.  It returns the number of ticks
  436. ** Note that this routine also builds the offset pointer
  437. ** array.
  438. */
  439. static ulong DoStringSortIteration(faruchar *arraybase,
  440.                 uint numarrays,ulong arraysize)
  441. {
  442. farulong *optrarray;            /* Offset pointer array */
  443. unsigned long elapsed;          /* Elapsed ticks */
  444. unsigned long nstrings;         /* # of strings in array */
  445. int syserror;                   /* System error code */
  446. unsigned int i;                 /* Index */
  447. farulong *tempobase;            /* Temporary offset pointer base */
  448. faruchar *tempsbase;            /* Temporary string base pointer */
  449.  
  450. /*
  451. ** Load up the array(s) with random numbers
  452. */
  453. optrarray=LoadStringArray(arraybase,numarrays,&nstrings,arraysize);
  454.  
  455. /*
  456. ** Set temp base pointers...they will be modified as the
  457. ** benchmark proceeds.
  458. */
  459. tempobase=optrarray;
  460. tempsbase=arraybase;
  461.  
  462. /*
  463. ** Start the stopwatch
  464. */
  465. elapsed=StartStopwatch();
  466.  
  467. /*
  468. ** Execute heapsorts
  469. */
  470. for(i=0;i<numarrays;i++)
  471. {       StrHeapSort(tempobase,tempsbase,nstrings,0L,nstrings-1);
  472.         tempobase+=nstrings;    /* Advance base pointers */
  473.         tempsbase+=arraysize+100;
  474. }
  475.  
  476. /*
  477. ** Record elapsed time
  478. */
  479. elapsed=StopStopwatch(elapsed);
  480.  
  481. #ifdef DEBUG
  482. {
  483.         unsigned long i;
  484.         for(i=0;i<nstrings-1;i++)
  485.         {       /*
  486.                 ** Compare strings to check for proper
  487.                 ** sort.
  488.                 */
  489.                 if(str_is_less(optrarray,arraybase,nstrings,i+1,i))
  490.                 {       printf("Sort Error\n");
  491.                         break;
  492.                 }
  493.         }
  494. }
  495. #endif
  496.  
  497. /*
  498. ** Release the offset pointer array built by
  499. ** LoadStringArray()
  500. */
  501. FreeMemory((farvoid *)optrarray,&syserror);
  502.  
  503. /*
  504. ** Return elapsed ticks.
  505. */
  506. return(elapsed);
  507. }
  508.  
  509. /********************
  510. ** LoadStringArray **
  511. *********************
  512. ** Initialize the string array with random strings of
  513. ** varying sizes.
  514. ** Returns the pointer to the offset pointer array.
  515. ** Note that since we're creating a number of arrays, this
  516. ** routine builds one array, then copies it into the others.
  517. */
  518. static farulong *LoadStringArray(faruchar *strarray, /* String array */
  519.         uint numarrays,                 /* # of arrays */
  520.         ulong *nstrings,                /* # of strings */
  521.         ulong arraysize)                /* Size of array */
  522. {
  523. faruchar *tempsbase;            /* Temporary string base pointer */
  524. farulong *optrarray;            /* Local for pointer */
  525. farulong *tempobase;            /* Temporary offset pointer base pointer */
  526. unsigned long curroffset;       /* Current offset */
  527. int fullflag;                   /* Indicates full array */
  528. unsigned char stringlength;     /* Length of string */
  529. unsigned char i;                /* Index */
  530. unsigned long j;                /* Another index */
  531. unsigned int k;                 /* Yet another index */
  532. unsigned int l;                 /* Ans still one more index */
  533. int systemerror;                /* For holding error code */
  534.  
  535. /*
  536. ** Initialize random number generator.
  537. */
  538. randnum(13L);
  539.  
  540. /*
  541. ** Start with no strings.  Initialize our current offset pointer
  542. ** to 0.
  543. */
  544. *nstrings=0L;
  545. curroffset=0L;
  546. fullflag=0;
  547.  
  548. do
  549. {
  550.         /*
  551.         ** Allocate a string with a random length no
  552.         ** shorter than 4 bytes and no longer than
  553.         ** 80 bytes.  Note we have to also make sure
  554.         ** there's room in the array.
  555.         */
  556.         stringlength=(unsigned char)(1+abs_randwc(76L) & 0xFFL);
  557.         if((unsigned long)stringlength+curroffset+1L>=arraysize)
  558.         {       stringlength=(unsigned char)((arraysize-curroffset-1L) &
  559.                                 0xFF);
  560.                 fullflag=1;     /* Indicates a full */
  561.         }
  562.  
  563.         /*
  564.         ** Store length at curroffset and advance current offset.
  565.         */
  566.         *(strarray+curroffset)=stringlength;
  567.         curroffset++;
  568.  
  569.         /*
  570.         ** Fill up the rest of the string with random bytes.
  571.         */
  572.         for(i=0;i<stringlength;i++)
  573.         {       *(strarray+curroffset)=
  574.                         (unsigned char)(abs_randwc((long)0xFE));
  575.                 curroffset++;
  576.         }
  577.  
  578.         /*
  579.         ** Increment the # of strings counter.
  580.         */
  581.         *nstrings+=1L;
  582.  
  583. } while(fullflag==0);
  584.  
  585. /*
  586. ** We now have initialized a single full array.  If there
  587. ** is more than one array, copy the original into the
  588. ** others.
  589. */
  590. k=1;
  591. tempsbase=strarray;
  592. while(k<numarrays)
  593. {       tempsbase+=arraysize+100;         /* Set base */
  594.         for(l=0;l<arraysize;l++)
  595.                 tempsbase[l]=strarray[l];
  596.         k++;
  597. }
  598.  
  599. /*
  600. ** Now the array is full, allocate enough space for an
  601. ** offset pointer array.
  602. */
  603. optrarray=(farulong *)AllocateMemory(*nstrings * sizeof(unsigned long) *
  604.                 numarrays,
  605.                 &systemerror);
  606. if(systemerror)
  607. {       ReportError("CPU:Stringsort",systemerror);
  608.         FreeMemory((void *)strarray,&systemerror);
  609.         ErrorExit();
  610. }
  611.  
  612. /*
  613. ** Go through the newly-built string array, building
  614. ** offsets and putting them into the offset pointer
  615. ** array.
  616. */
  617. curroffset=0;
  618. for(j=0;j<*nstrings;j++)
  619. {       *(optrarray+j)=curroffset;
  620.         curroffset+=(unsigned long)(*(strarray+curroffset))+1L;
  621. }
  622.  
  623. /*
  624. ** As above, we've made one copy of the offset pointers,
  625. ** so duplicate this array in the remaining ones.
  626. */
  627. k=1;
  628. tempobase=optrarray;
  629. while(k<numarrays)
  630. {       tempobase+=*nstrings;
  631.         for(l=0;l<*nstrings;l++)
  632.                 tempobase[l]=optrarray[l];
  633.         k++;
  634. }
  635.  
  636. /*
  637. ** All done...go home.  Pass local pointer back.
  638. */
  639. return(optrarray);
  640. }
  641.  
  642. /**************
  643. ** stradjust **
  644. ***************
  645. ** Used by the string heap sort.  Call this routine to adjust the
  646. ** string at offset i to length l.  The members of the string array
  647. ** are moved accordingly and the length of the string at offset i
  648. ** is set to l.
  649. */
  650. static void stradjust(farulong *optrarray,      /* Offset pointer array */
  651.         faruchar *strarray,                     /* String array */
  652.         ulong nstrings,                         /* # of strings */
  653.         ulong i,                                /* Offset to adjust */
  654.         uchar l)                                /* New length */
  655. {
  656. unsigned long nbytes;           /* # of bytes to move */
  657. unsigned long j;                /* Index */
  658. int direction;                  /* Direction indicator */
  659. unsigned char adjamount;        /* Adjustment amount */
  660.  
  661. /*
  662. ** If new length is less than old length, the direction is
  663. ** down.  If new length is greater than old length, the
  664. ** direction is up.
  665. */
  666. direction=(int)l - (int)*(strarray+*(optrarray+i));
  667. adjamount=(unsigned char)abs(direction);
  668.  
  669. /*
  670. ** See if the adjustment is being made to the last
  671. ** string in the string array.  If so, we don't have to
  672. ** do anything more than adjust the length field.
  673. */
  674. if(i==(nstrings-1L))
  675. {       *(strarray+*(optrarray+i))=l;
  676.         return;
  677. }
  678.  
  679. /*
  680. ** Calculate the total # of bytes in string array from
  681. ** location i+1 to end of array.  Whether we're moving "up" or
  682. ** down, this is how many bytes we'll have to move.
  683. */
  684. nbytes=*(optrarray+nstrings-1L) +
  685.         (unsigned long)*(strarray+*(optrarray+nstrings-1L)) + 1L -
  686.         *(optrarray+i+1L);
  687.  
  688. /*
  689. ** Calculate the source and the destination.  Source is
  690. ** string position i+1.  Destination is string position i+l
  691. ** (i+"ell"...don't confuse 1 and l).
  692. ** Hand this straight to memmove and let it handle the
  693. ** "overlap" problem.
  694. */
  695. MoveMemory((farvoid *)(strarray+*(optrarray+i)+l+1),
  696.         (farvoid *)(strarray+*(optrarray+i+1)),
  697.         (unsigned long)nbytes);
  698.  
  699. /*
  700. ** We have to adjust the offset pointer array.
  701. ** This covers string i+1 to numstrings-1.
  702. */
  703. for(j=i+1;j<nstrings;j++)
  704.         if(direction<0)
  705.                 *(optrarray+j)=*(optrarray+j)-adjamount;
  706.         else
  707.                 *(optrarray+j)=*(optrarray+j)+adjamount;
  708.         
  709. /*
  710. ** Store the new length and go home.
  711. */
  712. *(strarray+*(optrarray+i))=l;
  713. return;
  714. }
  715.  
  716. /****************
  717. ** strheapsort **
  718. *****************
  719. ** Pass this routine a pointer to an array of unsigned char.
  720. ** The array is presumed to hold strings occupying at most
  721. ** 80 bytes (counts a byte count).
  722. ** This routine also needs a pointer to an array of offsets
  723. ** which represent string locations in the array, and
  724. ** an unsigned long indicating the number of strings
  725. ** in the array.
  726. */
  727. static void StrHeapSort(farulong *optrarray, /* Offset pointers */
  728.         faruchar *strarray,             /* Strings array */
  729.         ulong numstrings,               /* # of strings in array */
  730.         ulong bottom,                   /* Region to sort...bottom */
  731.         ulong top)                      /* Region to sort...top */
  732. {
  733. unsigned char temp[80];                 /* Used to exchange elements */
  734. unsigned char tlen;                     /* Temp to hold length */
  735. unsigned long i;                        /* Loop index */
  736.  
  737.  
  738. /*
  739. ** Build a heap in the array
  740. */
  741. for(i=(top/2L); i>0; --i)
  742.         strsift(optrarray,strarray,numstrings,i,top);
  743.  
  744. /*
  745. ** Repeatedly extract maximum from heap and place it at the
  746. ** end of the array.  When we get done, we'll have a sorted
  747. ** array.
  748. */
  749. for(i=top; i>0; --i)
  750. {       
  751.         strsift(optrarray,strarray,numstrings,0,i);
  752.  
  753.         /* temp = string[0] */
  754.         tlen=*strarray;
  755.         MoveMemory((farvoid *)&temp[0], /* Perform exchange */
  756.                 (farvoid *)strarray,
  757.                 (unsigned long)(tlen+1));
  758.  
  759.  
  760.         /* string[0]=string[i] */
  761.         tlen=*(strarray+*(optrarray+i));
  762.         stradjust(optrarray,strarray,numstrings,0,tlen);
  763.         MoveMemory((farvoid *)strarray,
  764.                 (farvoid *)(strarray+*(optrarray+i)),
  765.                 (unsigned long)(tlen+1));
  766.  
  767.         /* string[i]=temp */
  768.         tlen=temp[0];
  769.         stradjust(optrarray,strarray,numstrings,i,tlen);
  770.         MoveMemory((farvoid *)(strarray+*(optrarray+i)),
  771.                 (farvoid *)&temp[0],
  772.                 (unsigned long)(tlen+1));
  773.  
  774. }
  775. return;
  776. }
  777.  
  778. /****************
  779. ** str_is_less **
  780. *****************
  781. ** Pass this function:
  782. **      1) A pointer to an array of offset pointers
  783. **      2) A pointer to a string array
  784. **      3) The number of elements in the string array
  785. **      4) Offsets to two strings (a & b)
  786. ** This function returns TRUE if string a is < string b.
  787. */
  788. static int str_is_less(farulong *optrarray, /* Offset pointers */
  789.         faruchar *strarray,                     /* String array */
  790.         ulong numstrings,                       /* # of strings */
  791.         ulong a, ulong b)                       /* Offsets */
  792. {
  793. int slen;               /* String length */
  794.  
  795. /*
  796. ** Determine which string has the minimum length.  Use that
  797. ** to call strncmp().  If they match up to that point, the
  798. ** string with the longer length wins.
  799. */
  800. slen=(int)*(strarray+*(optrarray+a));
  801. if(slen > (int)*(strarray+*(optrarray+b)))
  802.         slen=(int)*(strarray+*(optrarray+b));
  803.  
  804. slen=strncmp((char *)(strarray+*(optrarray+a)),
  805.                 (char *)(strarray+*(optrarray+b)),slen);
  806.  
  807. if(slen==0)
  808. {
  809.         /*
  810.         ** They match.  Return true if the length of a
  811.         ** is greater than the length of b.
  812.         */
  813.         if(*(strarray+*(optrarray+a)) >
  814.                 *(strarray+*(optrarray+b)))
  815.                 return(TRUE);
  816.         return(FALSE);
  817. }
  818.  
  819. if(slen<0) return(TRUE);        /* a is strictly less than b */
  820.  
  821. return(FALSE);                  /* Only other possibility */
  822. }
  823.  
  824. /************
  825. ** strsift **
  826. *************
  827. ** Pass this function:
  828. **      1) A pointer to an array of offset pointers
  829. **      2) A pointer to a string array
  830. **      3) The number of elements in the string array
  831. **      4) Offset within which to sort.
  832. ** Sift the array within the bounds of those offsets (thus
  833. ** building a heap).
  834. */
  835. static void strsift(farulong *optrarray,        /* Offset pointers */
  836.         faruchar *strarray,                     /* String array */
  837.         ulong numstrings,                       /* # of strings */
  838.         ulong i, ulong j)                       /* Offsets */
  839. {
  840. unsigned long k;                /* Temporaries */
  841. unsigned char temp[80];
  842. unsigned char tlen;             /* For string lengths */
  843.  
  844.  
  845. while((i+i)<=j)
  846. {
  847.         k=i+i;
  848.         if(k<j)
  849.                 if(str_is_less(optrarray,strarray,numstrings,k,k+1L))
  850.                         ++k;
  851.         if(str_is_less(optrarray,strarray,numstrings,i,k))
  852.         {
  853.                 /* temp=string[k] */
  854.                 tlen=*(strarray+*(optrarray+k));
  855.                 MoveMemory((farvoid *)&temp[0],
  856.                         (farvoid *)(strarray+*(optrarray+k)),
  857.                         (unsigned long)(tlen+1));
  858.  
  859.                 /* string[k]=string[i] */
  860.                 tlen=*(strarray+*(optrarray+i));
  861.                 stradjust(optrarray,strarray,numstrings,k,tlen);
  862.                 MoveMemory((farvoid *)(strarray+*(optrarray+k)),
  863.                         (farvoid *)(strarray+*(optrarray+i)),
  864.                         (unsigned long)(tlen+1));
  865.  
  866.                 /* string[i]=temp */
  867.                 tlen=temp[0];
  868.                 stradjust(optrarray,strarray,numstrings,i,tlen);
  869.                 MoveMemory((farvoid *)(strarray+*(optrarray+i)),
  870.                         (farvoid *)&temp[0],
  871.                         (unsigned long)(tlen+1));
  872.                 i=k;
  873.         }
  874.         else
  875.                 i=j+1;
  876. }
  877. return;
  878. }
  879.  
  880. /************************
  881. ** BITFIELD OPERATIONS **
  882. *************************/
  883.  
  884. /*************
  885. ** DoBitops **
  886. **************
  887. ** Perform the bit operations test portion of the CPU
  888. ** benchmark.  Returns the iterations per second.
  889. */
  890. void DoBitops(void)
  891. {
  892. BitOpStruct *locbitopstruct;    /* Local bitop structure */
  893. farulong *bitarraybase;         /* Base of bitmap array */
  894. farulong *bitoparraybase;       /* Base of bitmap operations array */
  895. ulong nbitops;                  /* # of bitfield operations */
  896. ulong accumtime;                /* Accumulated time in ticks */
  897. double iterations;              /* # of iterations */
  898. char *errorcontext;             /* Error context string */
  899. int systemerror;                /* For holding error codes */
  900.  
  901. /*
  902. ** Link to global structure.
  903. */
  904. locbitopstruct=&global_bitopstruct;
  905.  
  906. /*
  907. ** Set the error context.
  908. */
  909. errorcontext="CPU:Bitfields";
  910.  
  911. /*
  912. ** See if we need to run adjustment code.
  913. */
  914. if(locbitopstruct->adjust==0)
  915. {
  916.         bitarraybase=(farulong *)AllocateMemory(locbitopstruct->bitfieldarraysize *
  917.                 sizeof(ulong),&systemerror);
  918.         if(systemerror)
  919.         {       ReportError(errorcontext,systemerror);
  920.                 ErrorExit();
  921.         }
  922.  
  923.         /*
  924.         ** Initialize bitfield operations array to [2,30] elements
  925.         */
  926.         locbitopstruct->bitoparraysize=30L;
  927.  
  928.         while(1)
  929.         {
  930.                 /*
  931.                 ** Allocate space for operations array
  932.                 */
  933.                 bitoparraybase=(farulong *)AllocateMemory(locbitopstruct->bitoparraysize*2L*
  934.                         sizeof(ulong),
  935.                         &systemerror);
  936.                 if(systemerror)
  937.                 {       ReportError(errorcontext,systemerror);
  938.                         FreeMemory((farvoid *)bitarraybase,&systemerror);
  939.                         ErrorExit();
  940.                 }
  941.                 /*
  942.                 ** Do an iteration of the bitmap test.  If the
  943.                 ** elapsed time is less than or equal to the permitted
  944.                 ** minimum, then de-allocate the array, reallocate a
  945.                 ** larger version, and try again.
  946.                 */
  947.                 if(DoBitfieldIteration(bitarraybase,
  948.                         bitoparraybase,
  949.                         locbitopstruct->bitoparraysize,
  950.                         &nbitops)>global_min_ticks)
  951.                 break;          /* We're ok...exit */
  952.  
  953.                 FreeMemory((farvoid *)bitoparraybase,&systemerror);
  954.                 locbitopstruct->bitoparraysize+=100L;
  955.         }
  956. }
  957. else             
  958. {
  959.         /*
  960.         ** Don't need to do self adjustment, just allocate
  961.         ** the array space.
  962.         */
  963.         bitarraybase=(farulong *)AllocateMemory(locbitopstruct->bitfieldarraysize *
  964.                 sizeof(ulong),&systemerror);
  965.         if(systemerror)
  966.         {       ReportError(errorcontext,systemerror);
  967.                 ErrorExit();
  968.         }
  969.         bitoparraybase=(farulong *)AllocateMemory(locbitopstruct->bitoparraysize*2L*
  970.                 sizeof(ulong),
  971.                 &systemerror);
  972.         if(systemerror)
  973.         {       ReportError(errorcontext,systemerror);
  974.                 FreeMemory((farvoid *)bitarraybase,&systemerror);
  975.                 ErrorExit();
  976.         }
  977. }
  978.  
  979. /*
  980. ** All's well if we get here.  Repeatedly perform bitops until the
  981. ** accumulated elapsed time is greater than # of seconds requested.
  982. */
  983. accumtime=0L;
  984. iterations=(double)0.0;
  985. do {
  986.         accumtime+=DoBitfieldIteration(bitarraybase,
  987.                         bitoparraybase,
  988.                         locbitopstruct->bitoparraysize,&nbitops);
  989.         iterations+=(double)nbitops;
  990. } while(TicksToSecs(accumtime)<locbitopstruct->request_secs);
  991.  
  992. /*
  993. ** Clean up, calculate results, and go home.
  994. ** Also, set adjustment flag to show that we don't have
  995. ** to do self adjusting in the future.
  996. */
  997. FreeMemory((farvoid *)bitarraybase,&systemerror);
  998. FreeMemory((farvoid *)bitoparraybase,&systemerror);
  999. locbitopstruct->bitopspersec=iterations /TicksToFracSecs(accumtime);
  1000. if(locbitopstruct->adjust==0)
  1001.         locbitopstruct->adjust=1;
  1002.  
  1003. return;
  1004. }
  1005.  
  1006. /************************
  1007. ** DoBitfieldIteration **
  1008. *************************
  1009. ** Perform a single iteration of the bitfield benchmark.
  1010. ** Return the # of ticks accumulated by the operation.
  1011. */
  1012. static ulong DoBitfieldIteration(farulong *bitarraybase,
  1013.                 farulong *bitoparraybase,
  1014.                 long bitoparraysize,
  1015.                 ulong *nbitops)
  1016. {
  1017. long i;                         /* Index */
  1018. ulong bitoffset;                /* Offset into bitmap */
  1019. ulong elapsed;                  /* Time to execute */
  1020.  
  1021. /*
  1022. ** Clear # bitops counter
  1023. */
  1024. *nbitops=0L;
  1025.  
  1026. /*
  1027. ** Construct a set of bitmap offsets and run lengths.
  1028. ** The offset can be any random number from 0 to the
  1029. ** size of the bitmap (in bits).  The run length can
  1030. ** be any random number from 1 to the number of bits
  1031. ** between the offset and the end of the bitmap.
  1032. ** Note that the bitmap has 8192 * 32 bits in it.
  1033. ** (262,144 bits)
  1034. */
  1035. for (i=0;i<bitoparraysize;i++)
  1036. {
  1037.         /* First item is offset */
  1038.         *(bitoparraybase+i+i)=bitoffset=abs_randwc(262140L);
  1039.  
  1040.         /* Next item is run length */
  1041.         *nbitops+=*(bitoparraybase+i+i+1L)=abs_randwc(262140L-bitoffset);
  1042. }
  1043.  
  1044. /*
  1045. ** Array of offset and lengths built...do an iteration of
  1046. ** the test.
  1047. ** Start the stopwatch.
  1048. */
  1049. elapsed=StartStopwatch();
  1050.  
  1051. /*
  1052. ** Loop through array off offset/run length pairs.
  1053. ** Execute operation based on modulus of index.
  1054. */
  1055. for(i=0;i<bitoparraysize;i++)
  1056. {
  1057.         switch(i % 3)
  1058.         {
  1059.  
  1060.                 case 0: /* Set run of bits */
  1061.                         ToggleBitRun(bitarraybase,
  1062.                                 *(bitoparraybase+i+i),
  1063.                                 *(bitoparraybase+i+i+1),
  1064.                                 1);
  1065.                         break;
  1066.  
  1067.                 case 1: /* Clear run of bits */
  1068.                         ToggleBitRun(bitarraybase,
  1069.                                 *(bitoparraybase+i+i),
  1070.                                 *(bitoparraybase+i+i+1),
  1071.                                 0);
  1072.                         break;
  1073.  
  1074.                 case 2: /* Complement run of bits */
  1075.                         FlipBitRun(bitarraybase,
  1076.                                 *(bitoparraybase+i+i),
  1077.                                 *(bitoparraybase+i+i+1));
  1078.                         break;
  1079.         }
  1080. }
  1081.  
  1082. /*
  1083. ** Return elapsed time
  1084. */
  1085. return(StopStopwatch(elapsed));
  1086. }
  1087.  
  1088.  
  1089. /*****************************
  1090. **     ToggleBitRun          *
  1091. ******************************
  1092. ** Set or clear a run of nbits starting at
  1093. ** bit_addr in bitmap.
  1094. */
  1095. static void ToggleBitRun(farulong *bitmap, /* Bitmap */
  1096.                 ulong bit_addr,         /* Address of bits to set */
  1097.                 ulong nbits,            /* # of bits to set/clr */
  1098.                 uint val)               /* 1 or 0 */
  1099. {
  1100. unsigned long bindex;   /* Index into array */
  1101. unsigned long bitnumb;  /* Bit number */
  1102.  
  1103. while(nbits--)
  1104. {
  1105. #ifdef LONG64
  1106.         bindex=bit_addr>>6;     /* Index is number /64 */
  1107.         bindex=bit_addr % 64;   /* Bit number in word */
  1108. #else
  1109.         bindex=bit_addr>>5;     /* Index is number /32 */
  1110.         bitnumb=bit_addr % 32;  /* bit number in word */
  1111. #endif
  1112.         if(val)
  1113.                 bitmap[bindex]|=(1L<<bitnumb);
  1114.         else
  1115.                 bitmap[bindex]&=~(1L<<bitnumb);
  1116.         bit_addr++;
  1117. }
  1118. return;
  1119. }
  1120.  
  1121. /***************
  1122. ** FlipBitRun **
  1123. ****************
  1124. ** Complements a run of bits.
  1125. */
  1126. static void FlipBitRun(farulong *bitmap,        /* Bit map */
  1127.                 ulong bit_addr,                 /* Bit address */
  1128.                 ulong nbits)                    /* # of bits to flip */
  1129. {
  1130. unsigned long bindex;   /* Index into array */
  1131. unsigned long bitnumb;  /* Bit number */
  1132.  
  1133. while(nbits--)
  1134. {
  1135. #ifdef LONG64
  1136.         bindex=bit_addr>>6;     /* Index is number /64 */
  1137.         bitnumb=bit_addr % 32;  /* Bit number in longword */
  1138. #else
  1139.         bindex=bit_addr>>5;     /* Index is number /32 */
  1140.         bitnumb=bit_addr % 32;  /* Bit number in longword */
  1141. #endif
  1142.         bitmap[bindex]^=(1L<<bitnumb);
  1143.         bit_addr++;
  1144. }
  1145.  
  1146. return;
  1147. }
  1148.  
  1149. /*****************************
  1150. ** FLOATING-POINT EMULATION **
  1151. *****************************/
  1152.  
  1153. /**************
  1154. ** DoEmFloat **
  1155. ***************
  1156. ** Perform the floating-point emulation routines portion of the
  1157. ** CPU benchmark.  Returns the operations per second.
  1158. */
  1159. void DoEmFloat(void)
  1160. {
  1161. EmFloatStruct *locemfloatstruct;        /* Local structure */
  1162. InternalFPF *abase;             /* Base of A array */
  1163. InternalFPF *bbase;             /* Base of B array */
  1164. InternalFPF *cbase;             /* Base of C array */
  1165. ulong accumtime;                /* Accumulated time in ticks */
  1166. double iterations;              /* # of iterations */
  1167. ulong tickcount;                /* # of ticks */
  1168. char *errorcontext;             /* Error context string pointer */
  1169. int systemerror;                /* For holding error code */
  1170. ulong loops;                    /* # of loops */
  1171.  
  1172. /*
  1173. ** Link to global structure
  1174. */
  1175. locemfloatstruct=&global_emfloatstruct;
  1176.  
  1177. /*
  1178. ** Set the error context
  1179. */
  1180. errorcontext="CPU:Floating Emulation";
  1181.  
  1182.  
  1183. /*
  1184. ** Test the emulation routines.
  1185. */
  1186. #ifdef DEBUG
  1187. #endif
  1188.  
  1189. abase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
  1190.                 &systemerror);
  1191. if(systemerror)
  1192. {       ReportError(errorcontext,systemerror);
  1193.         ErrorExit();
  1194. }
  1195.  
  1196. bbase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
  1197.                 &systemerror);
  1198. if(systemerror)
  1199. {       ReportError(errorcontext,systemerror);
  1200.         FreeMemory((farvoid *)abase,&systemerror);
  1201.         ErrorExit();
  1202. }
  1203.  
  1204. cbase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
  1205.                 &systemerror);
  1206. if(systemerror)
  1207. {       ReportError(errorcontext,systemerror);
  1208.         FreeMemory((farvoid *)abase,&systemerror);
  1209.         FreeMemory((farvoid *)bbase,&systemerror);
  1210.         ErrorExit();
  1211. }
  1212.  
  1213. /*
  1214. ** Set up the arrays
  1215. */
  1216. SetupCPUEmFloatArrays(abase,bbase,cbase,locemfloatstruct->arraysize);
  1217.  
  1218. /*
  1219. ** See if we need to do self-adjusting code.
  1220. */
  1221. if(locemfloatstruct->adjust==0)
  1222. {
  1223.         locemfloatstruct->loops=0;
  1224.  
  1225.         /*
  1226.         ** Do an iteration of the tests.  If the elapsed time is
  1227.         ** less than minimum, increase the loop count and try
  1228.         ** again. 
  1229.         */
  1230.         for(loops=1;loops<CPUEMFLOATLOOPMAX;loops+=loops)
  1231.         {       tickcount=DoEmFloatIteration(abase,bbase,cbase,
  1232.                         locemfloatstruct->arraysize,
  1233.                         loops);
  1234.                 if(tickcount>global_min_ticks)
  1235.                 {       locemfloatstruct->loops=loops;
  1236.                         break;
  1237.                 }
  1238.         }
  1239. }
  1240.  
  1241. /*
  1242. ** Verify that selft adjustment code worked.
  1243. */
  1244. if(locemfloatstruct->loops==0)
  1245. {       printf("CPU:EMFPU -- CMPUEMFLOATLOOPMAX limit hit\n");
  1246.         FreeMemory((farvoid *)abase,&systemerror);
  1247.         FreeMemory((farvoid *)bbase,&systemerror);
  1248.         FreeMemory((farvoid *)cbase,&systemerror);
  1249.         ErrorExit();
  1250. }
  1251.  
  1252. /*
  1253. ** All's well if we get here.  Repeatedly perform floating
  1254. ** tests until the accumulated time is greater than the
  1255. ** # of seconds requested.
  1256. ** Each iteration performs arraysize * 3 operations.
  1257. */
  1258. accumtime=0L;
  1259. iterations=(double)0.0;
  1260. do {
  1261.         accumtime+=DoEmFloatIteration(abase,bbase,cbase,
  1262.                         locemfloatstruct->arraysize,
  1263.                         locemfloatstruct->loops);
  1264.         iterations+=(double)1.0;
  1265. } while(TicksToSecs(accumtime)<locemfloatstruct->request_secs);
  1266.  
  1267.  
  1268. /*
  1269. ** Clean up, calculate results, and go home.
  1270. ** Also, indicate that adjustment is done.
  1271. */
  1272. FreeMemory((farvoid *)abase,&systemerror);
  1273. FreeMemory((farvoid *)bbase,&systemerror);
  1274. FreeMemory((farvoid *)cbase,&systemerror);
  1275.  
  1276. locemfloatstruct->emflops=(iterations*(double)locemfloatstruct->loops)/
  1277.                 (double)TicksToFracSecs(accumtime);
  1278. if(locemfloatstruct->adjust==0)
  1279.         locemfloatstruct->adjust=1;
  1280.  
  1281. return;
  1282. }
  1283.  
  1284. /*************************
  1285. ** FOURIER COEFFICIENTS **
  1286. *************************/
  1287.  
  1288. /**************
  1289. ** DoFourier **
  1290. ***************
  1291. ** Perform the transcendental/trigonometric portion of the
  1292. ** benchmark.  This benchmark calculates the first n
  1293. ** fourier coefficients of the function (x+1)^x defined
  1294. ** on the interval 0,2.
  1295. */
  1296. void DoFourier(void)
  1297. {
  1298. FourierStruct *locfourierstruct;        /* Local fourier struct */
  1299. fardouble *abase;               /* Base of A[] coefficients array */
  1300. fardouble *bbase;               /* Base of B[] coefficients array */
  1301. unsigned long accumtime;        /* Accumulated time in ticks */
  1302. double iterations;              /* # of iterations */
  1303. char *errorcontext;             /* Error context string pointer */
  1304. int systemerror;                /* For error code */
  1305.  
  1306. /*
  1307. ** Link to global structure
  1308. */
  1309. locfourierstruct=&global_fourierstruct;
  1310.  
  1311. /*
  1312. ** Set error context string
  1313. */
  1314. errorcontext="FPU:Transcendental";
  1315.  
  1316. /*
  1317. ** See if we need to do self-adjustment code.
  1318. */
  1319. if(locfourierstruct->adjust==0)
  1320. {
  1321.         locfourierstruct->arraysize=100L;       /* Start at 100 elements */
  1322.         while(1)
  1323.         {
  1324.  
  1325.                 abase=(fardouble *)AllocateMemory(locfourierstruct->arraysize*sizeof(double),
  1326.                                 &systemerror);
  1327.                 if(systemerror)
  1328.                 {       ReportError(errorcontext,systemerror);
  1329.                         ErrorExit();
  1330.                 }
  1331.  
  1332.                 bbase=(fardouble *)AllocateMemory(locfourierstruct->arraysize*sizeof(double),
  1333.                                 &systemerror);
  1334.                 if(systemerror)
  1335.                 {       ReportError(errorcontext,systemerror);
  1336.                         FreeMemory((void *)abase,&systemerror);
  1337.                         ErrorExit();
  1338.                 }
  1339.                 /*
  1340.                 ** Do an iteration of the tests.  If the elapsed time is
  1341.                 ** less than or equal to the permitted minimum, re-allocate
  1342.                 ** larger arrays and try again.
  1343.                 */
  1344.                 if(DoFPUTransIteration(abase,bbase,
  1345.                         locfourierstruct->arraysize)>global_min_ticks)
  1346.                         break;          /* We're ok...exit */
  1347.         
  1348.                 /*
  1349.                 ** Make bigger arrays and try again.
  1350.                 */
  1351.                 FreeMemory((farvoid *)abase,&systemerror);
  1352.                 FreeMemory((farvoid *)bbase,&systemerror);
  1353.                 locfourierstruct->arraysize+=50L;
  1354.         }
  1355. }
  1356. else
  1357. {       /*
  1358.         ** Don't need self-adjustment.  Just allocate the
  1359.         ** arrays, and go.
  1360.         */
  1361.         abase=(fardouble *)AllocateMemory(locfourierstruct->arraysize*sizeof(double),
  1362.                         &systemerror);
  1363.         if(systemerror)
  1364.         {       ReportError(errorcontext,systemerror);
  1365.                 ErrorExit();
  1366.         }
  1367.  
  1368.         bbase=(fardouble *)AllocateMemory(locfourierstruct->arraysize*sizeof(double),
  1369.                         &systemerror);
  1370.         if(systemerror)
  1371.         {       ReportError(errorcontext,systemerror);
  1372.                 FreeMemory((void *)abase,&systemerror);
  1373.                 ErrorExit();
  1374.         }
  1375. }
  1376. /*
  1377. ** All's well if we get here.  Repeatedly perform integration
  1378. ** tests until the accumulated time is greater than the
  1379. ** # of seconds requested.
  1380. */
  1381. accumtime=0L;
  1382. iterations=(double)0.0;
  1383. do {
  1384.         accumtime+=DoFPUTransIteration(abase,bbase,locfourierstruct->arraysize);
  1385.         iterations+=(double)locfourierstruct->arraysize*(double)2.0-(double)1.0;
  1386. } while(TicksToSecs(accumtime)<locfourierstruct->request_secs);                         
  1387.  
  1388.  
  1389. /*
  1390. ** Clean up, calculate results, and go home.
  1391. ** Also set adjustment flag to indicate no adjust code needed.
  1392. */
  1393. FreeMemory((farvoid *)abase,&systemerror);
  1394. FreeMemory((farvoid *)bbase,&systemerror);
  1395.  
  1396. locfourierstruct->fflops=iterations/(double)TicksToFracSecs(accumtime);
  1397.  
  1398. if(locfourierstruct->adjust==0)
  1399.         locfourierstruct->adjust=1;
  1400.  
  1401. return;
  1402. }
  1403.  
  1404. /************************
  1405. ** DoFPUTransIteration **
  1406. *************************
  1407. ** Perform an iteration of the FPU Transcendental/trigonometric
  1408. ** benchmark.  Here, an iteration consists of calculating the
  1409. ** first n fourier coefficients of the function (x+1)^x on
  1410. ** the interval 0,2.  n is given by arraysize.
  1411. ** NOTE: The # of integration steps is fixed at
  1412. ** 200.
  1413. */
  1414. static ulong DoFPUTransIteration(fardouble *abase,      /* A coeffs. */
  1415.                         fardouble *bbase,               /* B coeffs. */
  1416.                         ulong arraysize)                /* # of coeffs */
  1417. {
  1418. double omega;           /* Fundamental frequency */
  1419. unsigned long i;        /* Index */
  1420. unsigned long elapsed;  /* Elapsed time */
  1421.  
  1422. /*
  1423. ** Start the stopwatch
  1424. */
  1425. elapsed=StartStopwatch();
  1426.  
  1427. /*
  1428. ** Calculate the fourier series.  Begin by
  1429. ** calculating A[0].
  1430. */
  1431.  
  1432. *abase=TrapezoidIntegrate((double)0.0,
  1433.                         (double)2.0,
  1434.                         200,
  1435.                         (double)0.0,    /* No omega * n needed */
  1436.                         0 )/(double)2.0;
  1437.  
  1438. /*
  1439. ** Calculate the fundamental frequency.
  1440. ** ( 2 * pi ) / period...and since the period
  1441. ** is 2, omega is simply pi.
  1442. */
  1443. omega=(double)3.1415926535897932;
  1444.  
  1445. for(i=1;i<arraysize;i++)
  1446. {
  1447.  
  1448.         /*
  1449.         ** Calculate A[i] terms.  Note, once again, that we
  1450.         ** can ignore the 2/period term outside the integral
  1451.         ** since the period is 2 and the term cancels itself
  1452.         ** out.
  1453.         */
  1454.         *(abase+i)=TrapezoidIntegrate((double)0.0,
  1455.                         (double)2.0,
  1456.                         200,
  1457.                         omega * (double)i,
  1458.                         1);     
  1459.  
  1460.         /*
  1461.         ** Calculate the B[i] terms.
  1462.         */
  1463.         *(bbase+i)=TrapezoidIntegrate((double)0.0,
  1464.                         (double)2.0,
  1465.                         200,
  1466.                         omega * (double)i,
  1467.                         2);
  1468.  
  1469. }
  1470.  
  1471. /*
  1472. ** All done, stop the stopwatch
  1473. */
  1474. return(StopStopwatch(elapsed));
  1475. }
  1476.  
  1477. /***********************
  1478. ** TrapezoidIntegrate **
  1479. ************************
  1480. ** Perform a simple trapezoid integration on the
  1481. ** function (x+1)**x.
  1482. ** x0,x1 set the lower and upper bounds of the
  1483. ** integration.
  1484. ** nsteps indicates # of trapezoidal sections
  1485. ** omegan is the fundamental frequency times
  1486. **  the series member #
  1487. ** select = 0 for the A[0] term, 1 for cosine terms, and
  1488. **   2 for sine terms.
  1489. ** Returns the value.
  1490. */
  1491. static double TrapezoidIntegrate( double x0,            /* Lower bound */
  1492.                         double x1,              /* Upper bound */
  1493.                         int nsteps,             /* # of steps */
  1494.                         double omegan,          /* omega * n */
  1495.                         int select)
  1496. {
  1497. double x;               /* Independent variable */
  1498. double dx;              /* Stepsize */
  1499. double rvalue;          /* Return value */
  1500.  
  1501.  
  1502. /*
  1503. ** Initialize independent variable
  1504. */
  1505. x=x0;
  1506.  
  1507. /*
  1508. ** Calculate stepsize
  1509. */
  1510. dx=(x1 - x0) / (double)nsteps;
  1511.  
  1512. /*
  1513. ** Initialize the return value.
  1514. */
  1515. rvalue=thefunction(x0,omegan,select)/(double)2.0;
  1516.  
  1517. /*
  1518. ** Compute the other terms of the integral.
  1519. */
  1520. if(nsteps!=1)
  1521. {       --nsteps;               /* Already done 1 step */
  1522.         while(--nsteps )
  1523.         {
  1524.                 x+=dx;
  1525.                 rvalue+=thefunction(x,omegan,select);
  1526.         }
  1527. }
  1528. /*
  1529. ** Finish computation
  1530. */
  1531. rvalue=(rvalue+thefunction(x1,omegan,select)/(double)2.0)*dx;
  1532.  
  1533. return(rvalue);
  1534. }
  1535.  
  1536. /****************
  1537. ** thefunction **
  1538. *****************
  1539. ** This routine selects the function to be used
  1540. ** in the Trapezoid integration.
  1541. ** x is the independent variable
  1542. ** omegan is omega * n
  1543. ** select chooses which of the sine/cosine functions
  1544. **  are used.  note the special case for select=0.
  1545. */
  1546. static double thefunction(double x,             /* Independent variable */
  1547.                 double omegan,          /* Omega * term */
  1548.                 int select)             /* Choose term */
  1549. {
  1550.  
  1551. /*
  1552. ** Use select to pick which function we call.
  1553. */
  1554. switch(select)
  1555. {
  1556.         case 0: return(pow(x+(double)1.0,x));
  1557.  
  1558.         case 1: return(pow(x+(double)1.0,x) * cos(omegan * x));
  1559.  
  1560.         case 2: return(pow(x+(double)1.0,x) * sin(omegan * x));
  1561. }
  1562.  
  1563. /*
  1564. ** We should never reach this point, but the following
  1565. ** keeps compilers from issuing a warning message.
  1566. */
  1567. return(0.0);
  1568. }
  1569.  
  1570. /*************************
  1571. ** ASSIGNMENT ALGORITHM **
  1572. *************************/
  1573.  
  1574. /*************
  1575. ** DoAssign **
  1576. **************
  1577. ** Perform an assignment algorithm.
  1578. ** The algorithm was adapted from the step by step guide found
  1579. ** in "Quantitative Decision Making for Business" (Gordon,
  1580. **  Pressman, and Cohn; Prentice-Hall)
  1581. **
  1582. **
  1583. ** NOTES:
  1584. ** 1. Even though the algorithm distinguishes between
  1585. **    ASSIGNROWS and ASSIGNCOLS, as though the two might
  1586. **    be different, it does presume a square matrix.
  1587. **    I.E., ASSIGNROWS and ASSIGNCOLS must be the same.
  1588. **    This makes for some algorithmically-correct but
  1589. **    probably non-optimal constructs.
  1590. **
  1591. */
  1592. void DoAssign(void)
  1593. {
  1594. AssignStruct *locassignstruct;  /* Local structure ptr */
  1595. farlong *arraybase;
  1596. char *errorcontext;
  1597. int systemerror;
  1598. ulong accumtime;
  1599. double iterations;
  1600.  
  1601. /*
  1602. ** Link to global structure
  1603. */
  1604. locassignstruct=&global_assignstruct;
  1605.  
  1606. /*
  1607. ** Set the error context string.
  1608. */
  1609. errorcontext="CPU:Assignment";                   
  1610.  
  1611. /*
  1612. ** See if we need to do self adjustment code.
  1613. */
  1614. if(locassignstruct->adjust==0)
  1615. {
  1616.         /*
  1617.         ** Self-adjustment code.  The system begins by working on 1
  1618.         ** array.  If it does that in no time, then two arrays
  1619.         ** are built.  This process continues until
  1620.         ** enough arrays are built to handle the tolerance.
  1621.         */
  1622.         locassignstruct->numarrays=1;
  1623.         while(1)
  1624.         {
  1625.                 /*
  1626.                 ** Allocate space for arrays
  1627.                 */
  1628.                 arraybase=(farlong *) AllocateMemory(sizeof(long)*
  1629.                         ASSIGNROWS*ASSIGNCOLS*locassignstruct->numarrays,
  1630.                          &systemerror);
  1631.                 if(systemerror)
  1632.                 {       ReportError(errorcontext,systemerror);
  1633.                         FreeMemory((farvoid *)arraybase,
  1634.                           &systemerror);
  1635.                         ErrorExit();
  1636.                 }
  1637.  
  1638.                 /*
  1639.                 ** Do an iteration of the assignment alg.  If the
  1640.                 ** elapsed time is less than or equal to the permitted
  1641.                 ** minimum, then allocate for more arrays and
  1642.                 ** try again.
  1643.                 */
  1644.                 if(DoAssignIteration(arraybase,
  1645.                         locassignstruct->numarrays)>global_min_ticks)
  1646.                         break;          /* We're ok...exit */
  1647.  
  1648.                 FreeMemory((farvoid *)arraybase, &systemerror);
  1649.                 locassignstruct->numarrays++;
  1650.         }
  1651. }
  1652. else
  1653. {       /*
  1654.         ** Allocate space for arrays
  1655.         */
  1656.         arraybase=(farlong *)AllocateMemory(sizeof(long)*
  1657.                 ASSIGNROWS*ASSIGNCOLS*locassignstruct->numarrays,
  1658.                  &systemerror);
  1659.         if(systemerror)
  1660.         {       ReportError(errorcontext,systemerror);
  1661.                 FreeMemory((farvoid *)arraybase,
  1662.                   &systemerror);
  1663.                 ErrorExit();
  1664.         }
  1665. }
  1666.  
  1667. /*
  1668. ** All's well if we get here.  Do the tests.
  1669. */
  1670. accumtime=0L;
  1671. iterations=(double)0.0;
  1672.  
  1673. do {
  1674.         accumtime+=DoAssignIteration(arraybase,
  1675.                 locassignstruct->numarrays);
  1676.         iterations+=(double)1.0;
  1677. } while(TicksToSecs(accumtime)<locassignstruct->request_secs);
  1678.  
  1679. /*
  1680. ** Clean up, calculate results, and go home.  Be sure to
  1681. ** show that we don't have to rerun adjustment code.
  1682. */
  1683. FreeMemory((farvoid *)arraybase,&systemerror);
  1684.  
  1685. locassignstruct->iterspersec=iterations * 
  1686.         (double)locassignstruct->numarrays / TicksToFracSecs(accumtime);
  1687.  
  1688. if(locassignstruct->adjust==0)
  1689.         locassignstruct->adjust=1;
  1690.  
  1691. return;
  1692.  
  1693. }
  1694.  
  1695. /**********************
  1696. ** DoAssignIteration **
  1697. ***********************
  1698. ** This routine executes one iteration of the assignment test.
  1699. ** It returns the number of ticks elapsed in the iteration.
  1700. */
  1701. static ulong DoAssignIteration(farlong *arraybase,
  1702.         ulong numarrays)
  1703. {
  1704. longptr abase;                  /* local pointer */
  1705. ulong elapsed;          /* Elapsed ticks */
  1706. ulong i;
  1707.  
  1708. /*
  1709. ** Set up local pointer
  1710. */
  1711. abase.ptrs.p=arraybase;
  1712.  
  1713. /*
  1714. ** Load up the arrays with a random table.
  1715. */
  1716. LoadAssignArrayWithRand(arraybase,numarrays);
  1717.  
  1718. /*
  1719. ** Start the stopwatch
  1720. */
  1721. elapsed=StartStopwatch();
  1722.  
  1723. /*
  1724. ** Execute assignment algorithms
  1725. */
  1726. for(i=0;i<numarrays;i++)
  1727. {       abase.ptrs.p+=i*ASSIGNROWS*ASSIGNCOLS;
  1728.         Assignment(*abase.ptrs.ap);
  1729. }
  1730.  
  1731. /*
  1732. ** Get elapsed time
  1733. */
  1734. return(StopStopwatch(elapsed));
  1735. }
  1736.  
  1737. /****************************
  1738. ** LoadAssignArrayWithRand **
  1739. *****************************
  1740. ** Load the assignment arrays with random numbers.  All positive.
  1741. ** These numbers represent costs.
  1742. */
  1743. static void LoadAssignArrayWithRand(farlong *arraybase,
  1744.         ulong numarrays)
  1745. {
  1746. longptr abase,abase1;   /* Local for array pointer */
  1747. ulong i;
  1748.  
  1749. /*
  1750. ** Set local array pointer
  1751. */
  1752. abase.ptrs.p=arraybase;
  1753. abase1.ptrs.p=arraybase;
  1754.  
  1755. /*
  1756. ** Set up the first array.  Then just copy it into the
  1757. ** others.
  1758. */
  1759. LoadAssign(*(abase.ptrs.ap));
  1760. if(numarrays>1)
  1761.         for(i=1;i<numarrays;i++)
  1762.         {       abase1.ptrs.p+=i*ASSIGNROWS*ASSIGNCOLS;
  1763.                 CopyToAssign(*(abase.ptrs.ap),*(abase1.ptrs.ap));
  1764.         }
  1765.  
  1766. return;
  1767. }
  1768.  
  1769. /***************
  1770. ** LoadAssign **
  1771. ****************
  1772. ** The array given by arraybase is loaded with positive random
  1773. ** numbers.  Elements in the array are capped at 5,000,000.
  1774. */
  1775. static void LoadAssign(farlong arraybase[][ASSIGNCOLS])
  1776. {
  1777. ushort i,j;
  1778.  
  1779. /*
  1780. ** Reset random number generator so things repeat.
  1781. */
  1782. randnum(13L);
  1783.  
  1784. for(i=0;i<ASSIGNROWS;i++)
  1785.         for(j=0;j<ASSIGNROWS;j++)
  1786.                 arraybase[i][j]=abs_randwc(5000000L);
  1787. return;
  1788. }
  1789.  
  1790. /*****************
  1791. ** CopyToAssign **
  1792. ******************
  1793. ** Copy the contents of one array to another.  This is called by
  1794. ** the routine that builds the initial array, and is used to copy
  1795. ** the contents of the intial array into all following arrays.
  1796. */
  1797. static void CopyToAssign(farlong arrayfrom[ASSIGNROWS][ASSIGNCOLS],
  1798.                 farlong arrayto[ASSIGNROWS][ASSIGNCOLS])
  1799. {
  1800. ushort i,j;
  1801.  
  1802. for(i=0;i<ASSIGNROWS;i++)
  1803.         for(j=0;j<ASSIGNCOLS;j++)
  1804.                 arrayto[i][j]=arrayfrom[i][j];
  1805.  
  1806. return;
  1807. }
  1808.  
  1809. /***************
  1810. ** Assignment **
  1811. ***************/
  1812. static void Assignment(farlong arraybase[][ASSIGNCOLS])
  1813. {
  1814. short assignedtableau[ASSIGNROWS][ASSIGNCOLS];
  1815.  
  1816. /*
  1817. ** First, calculate minimum costs
  1818. */
  1819. calc_minimum_costs(arraybase);
  1820.  
  1821. /*
  1822. ** Repeat following until the number of rows selected
  1823. ** equals the number of rows in the tableau.
  1824. */
  1825. while(first_assignments(arraybase,assignedtableau)!=ASSIGNROWS)
  1826. {         second_assignments(arraybase,assignedtableau);
  1827. }
  1828.  
  1829. #ifdef DEBUG
  1830. {
  1831.         int i,j;
  1832.         printf("Column choices for each row\n");
  1833.         for(i=0;i<ASSIGNROWS;i++)
  1834.         {
  1835.                 for(j=0;j<ASSIGNCOLS;j++)
  1836.                         if(assignedtableau[i][j]!=0)
  1837.                                 printf("%d ",j);
  1838.         }
  1839. }
  1840. #endif
  1841.  
  1842. return;
  1843. }
  1844.  
  1845. /***********************
  1846. ** calc_minimum_costs **
  1847. ************************
  1848. ** Revise the tableau by calculating the minimum costs on a
  1849. ** row and column basis.  These minima are subtracted from
  1850. ** their rows and columns, creating a new tableau.
  1851. */
  1852. static void calc_minimum_costs(long tableau[][ASSIGNCOLS])
  1853. {
  1854. ushort i,j;              /* Index variables */     
  1855. long currentmin;        /* Current minimum */        
  1856. /*
  1857. ** Determine minimum costs on row basis.  This is done by
  1858. ** subtracting -- on a row-per-row basis -- the minum value
  1859. ** for that row.
  1860. */
  1861. for(i=0;i<ASSIGNROWS;i++)
  1862. {
  1863.         currentmin=MAXPOSLONG;  /* Initialize minimum */
  1864.         for(j=0;j<ASSIGNCOLS;j++)
  1865.                 if(tableau[i][j]<currentmin)
  1866.                         currentmin=tableau[i][j];
  1867.  
  1868.         for(j=0;j<ASSIGNCOLS;j++)
  1869.                 tableau[i][j]-=currentmin;
  1870. }
  1871.  
  1872. /*
  1873. ** Determine minimum cost on a column basis.  This works
  1874. ** just as above, only now we step through the array
  1875. ** column-wise
  1876. */
  1877. for(j=0;j<ASSIGNCOLS;j++)
  1878. {
  1879.         currentmin=MAXPOSLONG;  /* Initialize minimum */
  1880.         for(i=0;i<ASSIGNROWS;i++)
  1881.                 if(tableau[i][j]<currentmin)
  1882.                         currentmin=tableau[i][j];
  1883.  
  1884.         /*
  1885.         ** Here, we'll take the trouble to see if the current
  1886.         ** minimum is zero.  This is likely worth it, since the
  1887.         ** preceding loop will have created at least one zero in
  1888.         ** each row.  We can save ourselves a few iterations.
  1889.         */
  1890.         if(currentmin!=0)
  1891.                 for(i=0;i<ASSIGNROWS;i++)
  1892.                         tableau[i][j]-=currentmin;
  1893. }
  1894.  
  1895. return;
  1896. }
  1897.  
  1898. /**********************
  1899. ** first_assignments **
  1900. ***********************
  1901. ** Do first assignments.
  1902. ** The assignedtableau[] array holds a set of values that
  1903. ** indicate the assignment of a value, or its elimination.
  1904. ** The values are:
  1905. **      0 = Item is neither assigned nor eliminated.
  1906. **      1 = Item is assigned
  1907. **      2 = Item is eliminated
  1908. ** Returns the number of selections made.  If this equals
  1909. ** the number of rows, then an optimum has been determined.
  1910. */
  1911. static int first_assignments(long tableau[][ASSIGNCOLS],
  1912.                 short assignedtableau[][ASSIGNCOLS])
  1913. {
  1914. ushort i,j,k;                   /* Index variables */
  1915. ushort numassigns;              /* # of assignments */
  1916. ushort totnumassigns;           /* Total # of assignments */
  1917. ushort numzeros;                /* # of zeros in row */
  1918. int selected;                   /* Flag used to indicate selection */    
  1919.  
  1920. /*
  1921. ** Clear the assignedtableau, setting all members to show that
  1922. ** no one is yet assigned, eliminated, or anything.
  1923. */
  1924. for(i=0;i<ASSIGNROWS;i++)
  1925.         for(j=0;j<ASSIGNCOLS;j++)
  1926.                 assignedtableau[i][j]=0;
  1927.  
  1928. totnumassigns=0;                
  1929. do {
  1930.         numassigns=0;
  1931.         /*
  1932.         ** Step through rows.  For each one that is not currently
  1933.         ** assigned, see if the row has only one zero in it.  If so,
  1934.         ** mark that as an assigned row/col.  Eliminate other zeros
  1935.         ** in the same column.
  1936.         */
  1937.         for(i=0;i<ASSIGNROWS;i++)
  1938.         {       numzeros=0;
  1939.                 for(j=0;j<ASSIGNCOLS;j++)
  1940.                         if(tableau[i][j]==0L)
  1941.                                 if(assignedtableau[i][j]==0)
  1942.                                 {       numzeros++;
  1943.                                         selected=j;
  1944.                                 }
  1945.                 if(numzeros==1)
  1946.                 {       numassigns++;
  1947.                         totnumassigns++;
  1948.                         assignedtableau[i][selected]=1;
  1949.                         for(k=0;k<ASSIGNROWS;k++)
  1950.                                 if((k!=i) &&
  1951.                                    (tableau[k][selected]==0))
  1952.                                         assignedtableau[k][selected]=2;
  1953.                 }
  1954.         }
  1955.         /*
  1956.         ** Step through columns, doing same as above.  Now, be careful
  1957.         ** of items in the other rows of a selected column.
  1958.         */
  1959.         for(j=0;j<ASSIGNCOLS;j++)
  1960.         {       numzeros=0;
  1961.                 for(i=0;i<ASSIGNROWS;i++)
  1962.                         if(tableau[i][j]==0L)
  1963.                                 if(assignedtableau[i][j]==0)
  1964.                                 {       numzeros++;
  1965.                                         selected=i;
  1966.                                 }
  1967.                 if(numzeros==1)
  1968.                 {       numassigns++;
  1969.                         totnumassigns++;
  1970.                         assignedtableau[selected][j]=1;
  1971.                         for(k=0;k<ASSIGNCOLS;k++)
  1972.                                 if((k!=j) &&
  1973.                                    (tableau[selected][k]==0))
  1974.                                         assignedtableau[selected][k]=2;
  1975.                 }
  1976.         }
  1977.         /*
  1978.         ** Repeat until no more assignments to be made.
  1979.         */
  1980. } while(numassigns!=0);
  1981.  
  1982. /*
  1983. ** See if we can leave at this point.
  1984. */
  1985. if(totnumassigns==ASSIGNROWS) return(totnumassigns);
  1986.  
  1987. /*
  1988. ** Now step through the array by row.  If you find any unassigned
  1989. ** zeros, pick the first in the row.  Eliminate all zeros from
  1990. ** that same row & column.  This occurs if there are multiple optima...
  1991. ** possibly.
  1992. */
  1993. for(i=0;i<ASSIGNROWS;i++)
  1994. {       selected=-1;
  1995.         for(j=0;j<ASSIGNCOLS;j++)
  1996.                 if((tableau[i][j]==0L) &&
  1997.                    (assignedtableau[i][j]==0))
  1998.                 {       selected=j;
  1999.                         break;
  2000.                 }
  2001.         if(selected!=-1)
  2002.         {       assignedtableau[i][selected]=1;
  2003.                 totnumassigns++;
  2004.                 for(k=0;k<ASSIGNCOLS;k++)
  2005.                         if((k!=selected) &&
  2006.                            (tableau[i][k]==0L))
  2007.                                 assignedtableau[i][k]=2;
  2008.                 for(k=0;k<ASSIGNROWS;k++)
  2009.                         if((k!=i) &&
  2010.                            (tableau[k][selected]==0L))
  2011.                                 assignedtableau[k][selected]=2;
  2012.         }
  2013. }
  2014.  
  2015. return(totnumassigns);
  2016. }
  2017.  
  2018. /***********************
  2019. ** second_assignments **
  2020. ************************
  2021. ** This section of the algorithm creates the revised
  2022. ** tableau, and is difficult to explain.  I suggest you
  2023. ** refer to the algorithm's source, mentioned in comments
  2024. ** toward the beginning of the program.
  2025. */
  2026. static void second_assignments(long tableau[][ASSIGNCOLS],
  2027.                 short assignedtableau[][ASSIGNCOLS])
  2028. {
  2029. int i,j;                                /* Indexes */  
  2030. short linesrow[ASSIGNROWS];
  2031. short linescol[ASSIGNCOLS];
  2032. long smallest;                          /* Holds smallest value */
  2033. ushort numassigns;                      /* Number of assignments */
  2034. ushort newrows;                         /* New rows to be considered */  
  2035. /*
  2036. ** Clear the linesrow and linescol arrays.
  2037. */
  2038. for(i=0;i<ASSIGNROWS;i++)
  2039.         linesrow[i]=0;
  2040. for(i=0;i<ASSIGNCOLS;i++)
  2041.         linescol[i]=0;
  2042.  
  2043. /*
  2044. ** Scan rows, flag each row that has no assignment in it.
  2045. */
  2046. for(i=0;i<ASSIGNROWS;i++)
  2047. {       numassigns=0;
  2048.         for(j=0;j<ASSIGNCOLS;j++)
  2049.                 if(assignedtableau[i][j]==1)
  2050.                 {       numassigns++;
  2051.                         break;
  2052.                 }
  2053.         if(numassigns==0) linesrow[i]=1;
  2054. }
  2055.  
  2056. do {
  2057.  
  2058.         newrows=0;
  2059.         /*
  2060.         ** For each row checked above, scan for any zeros.  If found,
  2061.         ** check the associated column.
  2062.         */
  2063.         for(i=0;i<ASSIGNROWS;i++)
  2064.         {       if(linesrow[i]==1)
  2065.                         for(j=0;j<ASSIGNCOLS;j++)
  2066.                                 if(tableau[i][j]==0)
  2067.                                         linescol[j]=1;
  2068.         }
  2069.  
  2070.         /*
  2071.         ** Now scan checked columns.  If any contain assigned zeros, check
  2072.         ** the associated row.
  2073.         */
  2074.         for(j=0;j<ASSIGNCOLS;j++)
  2075.                 if(linescol[j]==1)
  2076.                         for(i=0;i<ASSIGNROWS;i++)
  2077.                                 if((assignedtableau[i][j]==1) &&
  2078.                                         (linesrow[i]!=1))
  2079.                                 {
  2080.                                         linesrow[i]=1;
  2081.                                         newrows++;
  2082.                                 }
  2083. } while(newrows!=0);
  2084.  
  2085. /*
  2086. ** linesrow[n]==0 indicate rows covered by imaginary line
  2087. ** linescol[n]==1 indicate cols covered by imaginary line
  2088. ** For all cells not covered by imaginary lines, determine smallest
  2089. ** value.
  2090. */
  2091. smallest=MAXPOSLONG;
  2092. for(i=0;i<ASSIGNROWS;i++)
  2093.         if(linesrow[i]!=0)
  2094.                 for(j=0;j<ASSIGNCOLS;j++)
  2095.                         if(linescol[j]!=1)
  2096.                                 if(tableau[i][j]<smallest)
  2097.                                         smallest=tableau[i][j];
  2098.  
  2099. /*
  2100. ** Subtract smallest from all cells in the above set.
  2101. */
  2102. for(i=0;i<ASSIGNROWS;i++)
  2103.         if(linesrow[i]!=0)
  2104.                 for(j=0;j<ASSIGNCOLS;j++)
  2105.                         if(linescol[j]!=1)
  2106.                                 tableau[i][j]-=smallest;
  2107.  
  2108. /*
  2109. ** Add smallest to all cells covered by two lines.
  2110. */
  2111. for(i=0;i<ASSIGNROWS;i++)
  2112.         if(linesrow[i]==0)
  2113.                 for(j=0;j<ASSIGNCOLS;j++)
  2114.                         if(linescol[j]==1)
  2115.                                 tableau[i][j]+=smallest;
  2116.  
  2117. return;
  2118. }
  2119.  
  2120. /********************
  2121. ** IDEA Encryption **
  2122. *********************
  2123. ** IDEA - International Data Encryption Algorithm.
  2124. ** Based on code presented in Applied Cryptography by Bruce Schneier.
  2125. ** Which was based on code developed by Xuejia Lai and James L. Massey.
  2126. ** Other modifications made by Colin Plumb.
  2127. **
  2128. */
  2129.  
  2130. /***********
  2131. ** DoIDEA **
  2132. ************
  2133. ** Perform IDEA encryption.  Note that we time encryption & decryption
  2134. ** time as being a single loop.
  2135. */
  2136. void DoIDEA(void)
  2137. {
  2138. IDEAStruct *locideastruct;      /* Loc pointer to global structure */
  2139. int i;     
  2140. IDEAkey Z,DK;
  2141. u16 userkey[8];
  2142. ulong accumtime;
  2143. double iterations;
  2144. char *errorcontext;
  2145. int systemerror;
  2146. faruchar *plain1;               /* First plaintext buffer */
  2147. faruchar *crypt1;               /* Encryption buffer */
  2148. faruchar *plain2;               /* Second plaintext buffer */
  2149.  
  2150. /*
  2151. ** Link to global data
  2152. */
  2153. locideastruct=&global_ideastruct;
  2154.  
  2155. /*
  2156. ** Set error context
  2157. */
  2158. errorcontext="CPU:IDEA";
  2159.  
  2160. /*
  2161. ** Re-init random-number generator.
  2162. */
  2163. randnum(3L);
  2164.  
  2165. /*
  2166. ** Build an encryption/decryption key
  2167. */
  2168. for (i=0;i<8;i++)
  2169.         userkey[i]=(u16)(abs_randwc(60000L) & 0xFFFF);
  2170. for(i=0;i<KEYLEN;i++)
  2171.         Z[i]=0;
  2172.                 
  2173. /*
  2174. ** Compute encryption/decryption subkeys
  2175. */
  2176. en_key_idea(userkey,Z);
  2177. de_key_idea(Z,DK);
  2178.  
  2179. /*
  2180. ** Allocate memory for buffers.  We'll make 3, called plain1,
  2181. ** crypt1, and plain2.  It works like this:
  2182. **   plain1 >>encrypt>> crypt1 >>decrypt>> plain2.
  2183. ** So, plain1 and plain2 should match.
  2184. ** Also, fill up plain1 with sample text.       
  2185. */                                              
  2186. plain1=(faruchar *)AllocateMemory(locideastruct->arraysize,&systemerror);
  2187. if(systemerror)
  2188. {
  2189.         ReportError(errorcontext,systemerror);
  2190.         ErrorExit();
  2191. }
  2192.  
  2193. crypt1=(faruchar *)AllocateMemory(locideastruct->arraysize,&systemerror);
  2194. if(systemerror)
  2195. {
  2196.         ReportError(errorcontext,systemerror);
  2197.         FreeMemory((farvoid *)plain1,&systemerror);
  2198.         ErrorExit();
  2199. }
  2200.  
  2201. plain2=(faruchar *)AllocateMemory(locideastruct->arraysize,&systemerror);
  2202. if(systemerror)
  2203. {
  2204.         ReportError(errorcontext,systemerror);
  2205.         FreeMemory((farvoid *)plain1,&systemerror);
  2206.         FreeMemory((farvoid *)crypt1,&systemerror);
  2207.         ErrorExit();
  2208. }
  2209. /*
  2210. ** Note that we build the "plaintext" by simply loading
  2211. ** the array up with random numbers.
  2212. */
  2213. for(i=0;i<locideastruct->arraysize;i++)
  2214.         plain1[i]=(uchar)(abs_randwc(255) & 0xFF);
  2215.  
  2216. /*
  2217. ** See if we need to perform self adjustment loop.
  2218. */
  2219. if(locideastruct->adjust==0)
  2220. {
  2221.         /*
  2222.         ** Do self-adjustment.  This involves initializing the
  2223.         ** # of loops and increasing the loop count until we
  2224.         ** get a number of loops that we can use.
  2225.         */
  2226.         for(locideastruct->loops=100L;
  2227.           locideastruct->loops<MAXIDEALOOPS;
  2228.           locideastruct->loops+=10L)
  2229.                 if(DoIDEAIteration(plain1,crypt1,plain2,
  2230.                   locideastruct->arraysize,
  2231.                   locideastruct->loops,
  2232.                   Z,DK)>global_min_ticks) break;
  2233. }
  2234.  
  2235. /*
  2236. ** All's well if we get here.  Do the test.
  2237. */
  2238. accumtime=0L;                
  2239. iterations=(double)0.0;
  2240.  
  2241. do {
  2242.         accumtime+=DoIDEAIteration(plain1,crypt1,plain2,
  2243.                 locideastruct->arraysize,
  2244.                 locideastruct->loops,Z,DK);
  2245.         iterations+=(double)locideastruct->loops;
  2246. } while(TicksToSecs(accumtime)<locideastruct->request_secs);
  2247.  
  2248. /*
  2249. ** Clean up, calculate results, and go home.  Be sure to
  2250. ** show that we don't have to rerun adjustment code.
  2251. */
  2252. FreeMemory((farvoid *)plain1,&systemerror);
  2253. FreeMemory((farvoid *)crypt1,&systemerror);
  2254. FreeMemory((farvoid *)plain2,&systemerror);
  2255. locideastruct->iterspersec=iterations / TicksToFracSecs(accumtime);
  2256.  
  2257. if(locideastruct->adjust==0)
  2258.         locideastruct->adjust=1;
  2259.  
  2260. return;
  2261.  
  2262. }
  2263.  
  2264. /********************
  2265. ** DoIDEAIteration **
  2266. *********************
  2267. ** Execute a single iteration of the IDEA encryption algorithm.
  2268. ** Actually, a single iteration is one encryption and one
  2269. ** decryption.
  2270. */
  2271. static ulong DoIDEAIteration(faruchar *plain1,
  2272.                         faruchar *crypt1,
  2273.                         faruchar *plain2,
  2274.                         ulong arraysize,
  2275.                         ulong nloops,
  2276.                         IDEAkey Z,
  2277.                         IDEAkey DK)
  2278. {       
  2279. register ulong i;
  2280. register ulong j;
  2281. ulong elapsed;
  2282.  
  2283. /*
  2284. ** Start the stopwatch.
  2285. */
  2286. elapsed=StartStopwatch();
  2287.  
  2288. /*
  2289. ** Do everything for nloops.
  2290. */
  2291. for(i=0;i<nloops;i++)
  2292. {
  2293.         for(j=0;j<arraysize;j+=(sizeof(u16)*4))
  2294.                 cipher_idea((u16 *)(plain1+j),(u16 *)(crypt1+j),Z);       /* Encrypt */
  2295.  
  2296.         for(j=0;j<arraysize;j+=(sizeof(u16)*4))
  2297.                 cipher_idea((u16 *)(crypt1+j),(u16 *)(plain2+j),DK);      /* Decrypt */
  2298. }
  2299.  
  2300. #ifdef DEBUG
  2301. for(j=0;j<arraysize;j++)
  2302.         if(*(plain1+j)!=*(plain2+j))
  2303.                 printf("IDEA Error! \n");
  2304. #endif
  2305.  
  2306. /*
  2307. ** Get elapsed time.
  2308. */
  2309. return(StopStopwatch(elapsed));
  2310. }       
  2311.                 
  2312. /********
  2313. ** mul **
  2314. *********
  2315. ** Performs multiplication, modulo (2**16)+1.  This code is structured
  2316. ** on the assumption that untaken branches are cheaper than taken
  2317. ** branches, and that the compiler doesn't schedule branches.
  2318. */
  2319. static u16 mul(register u16 a, register u16 b)
  2320. {
  2321. register u32 p;
  2322. if(a)
  2323. {       if(b)
  2324.         {       p=(u32)(a*b);
  2325.                 b=low16(p);
  2326.                 a=(u16)(p>>16);
  2327.                 return((u16)(b-a+(b<a)));
  2328.         }
  2329.         else
  2330.                 return((u16)(1-a));
  2331. }
  2332. else
  2333.         return((u16)(1-b));
  2334. }
  2335.  
  2336. /********
  2337. ** inv **
  2338. *********
  2339. ** Compute multiplicative inverse of x, modulo (2**16)+1
  2340. ** using Euclid's GCD algorithm.  It is unrolled twice
  2341. ** to avoid swapping the meaning of the registers.  And
  2342. ** some subtracts are changed to adds.
  2343. */
  2344. static u16 inv(u16 x)
  2345. {
  2346. u16 t0, t1;
  2347. u16 q, y;
  2348.  
  2349. if(x<=1)
  2350.         return(x);      /* 0 and 1 are self-inverse */
  2351. t1=0x10001 / x;
  2352. y=0x10001 % x;
  2353. if(y==1)
  2354.         return((u16)low16(1-t1));
  2355. t0=1;
  2356. do {
  2357.         q=x/y;
  2358.         x=x%y;
  2359.         t0+=q*t1;
  2360.         if(x==1) return(t0);
  2361.         q=y/x;
  2362.         y=y%x;
  2363.         t1+=q*t0;
  2364. } while(y!=1);
  2365. return((u16)low16(1-t1));
  2366. }
  2367.  
  2368. /****************
  2369. ** en_key_idea **
  2370. *****************
  2371. ** Compute IDEA encryption subkeys Z
  2372. */
  2373. static void en_key_idea(u16 *userkey, u16 *Z)
  2374. {
  2375. int i,j;
  2376.  
  2377. /*
  2378. ** shifts
  2379. */
  2380. for(j=0;j<8;j++)
  2381.         Z[j]=*userkey++;
  2382. for(i=0;j<KEYLEN;j++)
  2383. {       i++;
  2384.         Z[i+7]=(Z[i&7]<<9)| (Z[(i+1) & 7] >> 7);
  2385.         Z+=i&8;
  2386.         i&=7;
  2387. }
  2388. return;
  2389. }
  2390.  
  2391. /****************
  2392. ** de_key_idea **
  2393. *****************
  2394. ** Compute IDEA decryption subkeys DK from encryption
  2395. ** subkeys Z.
  2396. */
  2397. static void de_key_idea(IDEAkey Z, IDEAkey DK)
  2398. {
  2399. IDEAkey TT;
  2400. int j;
  2401. u16 t1, t2, t3;
  2402. u16 *p;
  2403. p=(u16 *)(TT+KEYLEN);
  2404.  
  2405. t1=inv(*Z++);
  2406. t2=-*Z++;
  2407. t3=-*Z++;
  2408. *--p=inv(*Z++);
  2409. *--p=t3;
  2410. *--p=t2;
  2411. *--p=t1;
  2412.  
  2413. for(j=1;j<ROUNDS;j++)
  2414. {       t1=*Z++;
  2415.         *--p=*Z++;
  2416.         *--p=t1;
  2417.         t1=inv(*Z++);
  2418.         t2=-*Z++;
  2419.         t3=-*Z++;
  2420.         *--p=inv(*Z++);
  2421.         *--p=t2;
  2422.         *--p=t3;
  2423.         *--p=t1;
  2424. }
  2425. t1=*Z++;
  2426. *--p=*Z++;
  2427. *--p=t1;
  2428. t1=inv(*Z++);
  2429. t2=-*Z++;
  2430. t3=-*Z++;
  2431. *--p=inv(*Z++);
  2432. *--p=t3;
  2433. *--p=t2;
  2434. *--p=t1;
  2435. /*
  2436. ** Copy and destroy temp copy
  2437. */
  2438. for(j=0,p=TT;j<KEYLEN;j++)
  2439. {       *DK++=*p;
  2440.         *p++=0;
  2441. }
  2442.  
  2443. return;
  2444. }
  2445.  
  2446. /*
  2447. ** MUL(x,y)
  2448. ** This #define creates a macro that computes x=x*y modulo 0x10001.
  2449. ** Requires temps t16 and t32.  Also requires y to be strictly 16
  2450. ** bits.  Here, I am using the simplest form.  May not be the
  2451. ** fastest. -- RG
  2452. */
  2453. /* #define MUL(x,y) (x=mul(low16(x),y)) */
  2454.  
  2455. /****************
  2456. ** cipher_idea **
  2457. *****************
  2458. ** IDEA encryption/decryption algorithm.
  2459. */
  2460. static void cipher_idea(u16 in[4],
  2461.                 u16 out[4],
  2462.                 register IDEAkey Z)
  2463. {
  2464. register u16 x1, x2, x3, x4, t1, t2;
  2465. /* register u16 t16;
  2466. register u16 t32; */
  2467. int r=ROUNDS;
  2468.  
  2469. x1=*in++;
  2470. x2=*in++;
  2471. x3=*in++;
  2472. x4=*in;
  2473.  
  2474. do {
  2475.         MUL(x1,*Z++);
  2476.         x2+=*Z++;
  2477.         x3+=*Z++;
  2478.         MUL(x4,*Z++);
  2479.  
  2480.         t2=x1^x3;
  2481.         MUL(t2,*Z++);
  2482.         t1=t2+(x2^x4);
  2483.         MUL(t1,*Z++);
  2484.         t2=t1+t2;
  2485.  
  2486.         x1^=t1;
  2487.         x4^=t2;
  2488.         
  2489.         t2^=x2;
  2490.         x2=x3^t1;
  2491.         x3=t2;
  2492. } while(--r);
  2493. MUL(x1,*Z++);
  2494. *out++=x1;
  2495. *out++=x3+*Z++;
  2496. *out++=x2+*Z++;
  2497. MUL(x4,*Z);
  2498. *out=x4;
  2499. return;
  2500. }
  2501.  
  2502. /************************
  2503. ** HUFFMAN COMPRESSION **
  2504. ************************/
  2505.  
  2506. /**************
  2507. ** DoHuffman **
  2508. ***************
  2509. ** Execute a huffman compression on a block of plaintext.
  2510. ** Note that (as with IDEA encryption) an iteration of the
  2511. ** Huffman test includes a compression AND a decompression.
  2512. ** Also, the compression cycle includes building the
  2513. ** Huffman tree.
  2514. */
  2515. void DoHuffman(void)
  2516. {
  2517. HuffStruct *lochuffstruct;      /* Loc pointer to global data */
  2518. char *errorcontext;
  2519. int systemerror;
  2520. ulong accumtime;
  2521. double iterations;
  2522. farchar *comparray;
  2523. farchar *decomparray;
  2524. farchar *plaintext;
  2525.  
  2526. /*
  2527. ** Link to global data
  2528. */
  2529. lochuffstruct=&global_huffstruct;
  2530.  
  2531. /*
  2532. ** Set error context.
  2533. */
  2534. errorcontext="CPU:Huffman";
  2535.  
  2536. /*
  2537. ** Allocate memory for the plaintext and the compressed text.
  2538. ** We'll be really pessimistic here, and allocate equal amounts
  2539. ** for both (though we know...well, we PRESUME) the compressed
  2540. ** stuff will take less than the plain stuff.
  2541. ** Also note that we'll build a 3rd buffer to decompress
  2542. ** into, and we preallocate space for the huffman tree.
  2543. ** (We presume that the Huffman tree will grow no larger
  2544. ** than 512 bytes.  This is actually a super-conservative
  2545. ** estimate...but, who cares?)
  2546. */
  2547. plaintext=(farchar *)AllocateMemory(lochuffstruct->arraysize,&systemerror);
  2548. if(systemerror)
  2549. {       ReportError(errorcontext,systemerror);
  2550.         ErrorExit();
  2551. }
  2552. comparray=(farchar *)AllocateMemory(lochuffstruct->arraysize,&systemerror);
  2553. if(systemerror)
  2554. {       ReportError(errorcontext,systemerror);
  2555.         FreeMemory(plaintext,&systemerror);
  2556.         ErrorExit();
  2557. }
  2558. decomparray=(farchar *)AllocateMemory(lochuffstruct->arraysize,&systemerror);
  2559. if(systemerror)
  2560. {       ReportError(errorcontext,systemerror);
  2561.         FreeMemory(plaintext,&systemerror);
  2562.         FreeMemory(comparray,&systemerror);
  2563.         ErrorExit();
  2564. }
  2565.  
  2566. hufftree=(huff_node *)AllocateMemory(sizeof(huff_node) * 512,
  2567.         &systemerror);
  2568. if(systemerror)
  2569. {       ReportError(errorcontext,systemerror);
  2570.         FreeMemory(plaintext,&systemerror);
  2571.         FreeMemory(comparray,&systemerror);
  2572.         FreeMemory(decomparray,&systemerror);
  2573.         ErrorExit();
  2574. }
  2575.  
  2576. /*
  2577. ** Build the plaintext buffer.  Since we want this to
  2578. ** actually be able to compress, we'll use the
  2579. ** wordcatalog to build the plaintext stuff.
  2580. */
  2581. create_text_block(plaintext,lochuffstruct->arraysize-1,(ushort)500);
  2582. plaintext[lochuffstruct->arraysize-1L]='\0';
  2583. plaintextlen=lochuffstruct->arraysize;
  2584.  
  2585. /*
  2586. ** See if we need to perform self adjustment loop.
  2587. */
  2588. if(lochuffstruct->adjust==0)
  2589. {
  2590.         /*
  2591.         ** Do self-adjustment.  This involves initializing the
  2592.         ** # of loops and increasing the loop count until we
  2593.         ** get a number of loops that we can use.
  2594.         */
  2595.         for(lochuffstruct->loops=100L;
  2596.           lochuffstruct->loops<MAXHUFFLOOPS;
  2597.           lochuffstruct->loops+=10L)
  2598.                 if(DoHuffIteration(plaintext,
  2599.                         comparray,
  2600.                         decomparray,         
  2601.                   lochuffstruct->arraysize,
  2602.                   lochuffstruct->loops,
  2603.                   hufftree)>global_min_ticks) break;
  2604. }
  2605.  
  2606. /*
  2607. ** All's well if we get here.  Do the test.
  2608. */
  2609. accumtime=0L;
  2610. iterations=(double)0.0;
  2611.  
  2612. do {
  2613.         accumtime+=DoHuffIteration(plaintext,
  2614.                 comparray,
  2615.                 decomparray,
  2616.                 lochuffstruct->arraysize,
  2617.                 lochuffstruct->loops,
  2618.                 hufftree);
  2619.         iterations+=(double)lochuffstruct->loops;
  2620. } while(TicksToSecs(accumtime)<lochuffstruct->request_secs);
  2621.  
  2622. /*
  2623. ** Clean up, calculate results, and go home.  Be sure to
  2624. ** show that we don't have to rerun adjustment code.
  2625. */
  2626. FreeMemory((farvoid *)plaintext,&systemerror);
  2627. FreeMemory((farvoid *)comparray,&systemerror);
  2628. FreeMemory((farvoid *)decomparray,&systemerror);
  2629. FreeMemory((farvoid *)hufftree,&systemerror);
  2630. lochuffstruct->iterspersec=iterations / TicksToFracSecs(accumtime);
  2631.  
  2632. if(lochuffstruct->adjust==0)
  2633.         lochuffstruct->adjust=1;
  2634.  
  2635. }
  2636.  
  2637. /*********************
  2638. ** create_text_line **
  2639. **********************
  2640. ** Create a random line of text, stored at *dt.  The line may be
  2641. ** no more than nchars long.
  2642. */
  2643. static void create_text_line(farchar *dt,
  2644.                         long nchars)
  2645. {
  2646. long charssofar;        /* # of characters so far */
  2647. long tomove;            /* # of characters to move */
  2648. char myword[40];        /* Local buffer for words */
  2649. farchar *wordptr;       /* Pointer to word from catalog */       
  2650.  
  2651. charssofar=0;
  2652.  
  2653. do {
  2654. /*
  2655. ** Grab a random word from the wordcatalog
  2656. */
  2657. wordptr=wordcatarray[abs_randwc((long)WORDCATSIZE)];
  2658. MoveMemory((farvoid *)myword,
  2659.         (farvoid *)wordptr,
  2660.         (unsigned long)strlen(wordptr)+1);
  2661.  
  2662. /*
  2663. ** Append a blank.
  2664. */
  2665. tomove=strlen(myword)+1;
  2666. myword[tomove-1]=' ';
  2667.  
  2668. /*
  2669. ** See how long it is.  If its length+charssofar > nchars, we have
  2670. ** to trim it.
  2671. */
  2672. if((tomove+charssofar)>nchars)
  2673.         tomove=nchars-charssofar;
  2674. /*
  2675. ** Attach the word to the current line.  Increment counter.
  2676. */
  2677. MoveMemory((farvoid *)dt,(farvoid *)myword,(unsigned long)tomove);
  2678. charssofar+=tomove;
  2679. dt+=tomove;
  2680.  
  2681. /*
  2682. ** If we're done, bail out.  Otherwise, go get another word.
  2683. */
  2684. } while(charssofar<nchars);
  2685.  
  2686. return;
  2687. }
  2688.  
  2689. /**********************
  2690. ** create_text_block **
  2691. ***********************
  2692. ** Build a block of text randomly loaded with words.  The words
  2693. ** come from the wordcatalog (which must be loaded before you
  2694. ** call this).
  2695. ** *tb points to the memory where the text is to be built.
  2696. ** tblen is the # of bytes to put into the text block
  2697. ** maxlinlen is the maximum length of any line (line end indicated
  2698. **  by a carriage return).
  2699. */
  2700. static void create_text_block(farchar *tb,
  2701.                         ulong tblen,
  2702.                         ushort maxlinlen)
  2703. {
  2704. ulong bytessofar;       /* # of bytes so far */
  2705. ulong linelen;          /* Line length */
  2706.  
  2707. bytessofar=0L;  
  2708. do {
  2709.  
  2710. /*
  2711. ** Pick a random length for a line and fill the line.
  2712. ** Make sure the line can fit (haven't exceeded tablen) and also
  2713. ** make sure you leave room to append a carriage return.
  2714. */
  2715. linelen=abs_randwc(maxlinlen-6)+6;
  2716. if((linelen+bytessofar)>tblen)
  2717.         linelen=tblen-bytessofar;
  2718.  
  2719. if(linelen>1)
  2720. {
  2721.         create_text_line(tb,linelen);
  2722. }
  2723. tb+=linelen-1;          /* Add the carriage return */
  2724. *tb++='\n';
  2725.  
  2726. bytessofar+=linelen;
  2727.  
  2728. } while(bytessofar<tblen);
  2729.  
  2730. }
  2731.  
  2732. /********************
  2733. ** DoHuffIteration **
  2734. *********************
  2735. ** Perform the huffman benchmark.  This routine
  2736. **  (a) Builds the huffman tree
  2737. **  (b) Compresses the text
  2738. **  (c) Decompresses the text and verifies correct decompression
  2739. */
  2740. static ulong DoHuffIteration(farchar *plaintext,
  2741.         farchar *comparray,
  2742.         farchar *decomparray,
  2743.         ulong arraysize,
  2744.         ulong nloops,
  2745.         huff_node *hufftree)
  2746. {
  2747. int i;                          /* Index */
  2748. long j;                         /* Bigger index */
  2749. int root;                       /* Pointer to huffman tree root */
  2750. float lowfreq1, lowfreq2;       /* Low frequency counters */
  2751. int lowidx1, lowidx2;           /* Indexes of low freq. elements */
  2752. long bitoffset;                 /* Bit offset into text */
  2753. long textoffset;                /* Char offset into text */
  2754. long maxbitoffset;              /* Holds limit of bit offset */
  2755. long bitstringlen;              /* Length of bitstring */      
  2756. int c;                          /* Character from plaintext */
  2757. char bitstring[30];             /* Holds bitstring */   
  2758. ulong elapsed;                  /* For stopwatch */
  2759.  
  2760. /*
  2761. ** Start the stopwatch
  2762. */
  2763. elapsed=StartStopwatch();
  2764.  
  2765. /*
  2766. ** Do everything for nloops
  2767. */
  2768. while(nloops--)
  2769. {
  2770.  
  2771. /*
  2772. ** Calculate the frequency of each byte value. Store the
  2773. ** results in what will become the "leaves" of the
  2774. ** Huffman tree.  Interior nodes will be built in those
  2775. ** nodes greater than node #255.
  2776. */
  2777. for(i=0;i<256;i++)
  2778. {
  2779.         hufftree[i].freq=(float)0.0;
  2780.         hufftree[i].c=(unsigned char)i;
  2781. }
  2782.  
  2783. for(j=0;j<arraysize;j++)
  2784.         hufftree[plaintext[j]].freq+=(float)1.0;
  2785.  
  2786. for(i=0;i<256;i++)
  2787.         if(hufftree[i].freq != (float)0.0)
  2788.                 hufftree[i].freq/=(float)arraysize;
  2789.  
  2790. /*
  2791. ** Build the huffman tree.  First clear all the parent
  2792. ** pointers and left/right pointers.  Also, discard all
  2793. ** nodes that have a frequency of true 0.
  2794. */
  2795. for(i=0;i<512;i++)
  2796. {       if(hufftree[i].freq==(float)0.0)
  2797.                 hufftree[i].parent=EXCLUDED;
  2798.         else
  2799.                 hufftree[i].parent=hufftree[i].left=hufftree[i].right=-1;
  2800. }
  2801.  
  2802. /*
  2803. ** Go through the tree. Finding nodes of really low
  2804. ** frequency.
  2805. */
  2806. root=255;                       /* Starting root node-1 */
  2807. while(1)
  2808. {
  2809.         lowfreq1=(float)2.0; lowfreq2=(float)2.0;
  2810.         lowidx1=-1; lowidx2=-1;
  2811.         /*
  2812.         ** Find first lowest frequency.
  2813.         */
  2814.         for(i=0;i<=root;i++)
  2815.                 if(hufftree[i].parent<0)
  2816.                         if(hufftree[i].freq<lowfreq1)
  2817.                         {       lowfreq1=hufftree[i].freq;
  2818.                                 lowidx1=i;
  2819.                         }
  2820.  
  2821.         /*
  2822.         ** Did we find a lowest value?  If not, the
  2823.         ** tree is done.
  2824.         */
  2825.         if(lowidx1==-1) break;
  2826.  
  2827.         /*
  2828.         ** Find next lowest frequency
  2829.         */
  2830.         for(i=0;i<=root;i++)
  2831.                 if((hufftree[i].parent<0) && (i!=lowidx1))
  2832.                         if(hufftree[i].freq<lowfreq2)
  2833.                         {       lowfreq2=hufftree[i].freq;
  2834.                                 lowidx2=i;
  2835.                         }
  2836.  
  2837.         /*
  2838.         ** If we could only find one item, then that
  2839.         ** item is surely the root, and (as above) the
  2840.         ** tree is done.
  2841.         */
  2842.         if(lowidx2==-1) break;
  2843.                 
  2844.         /*
  2845.         ** Attach the two new nodes to the current root, and
  2846.         ** advance the current root.
  2847.         */
  2848.         root++;                 /* New root */ 
  2849.         hufftree[lowidx1].parent=root;
  2850.         hufftree[lowidx2].parent=root;
  2851.         hufftree[root].freq=lowfreq1+lowfreq2;
  2852.         hufftree[root].left=lowidx1;
  2853.         hufftree[root].right=lowidx2;
  2854.         hufftree[root].parent=-2;       /* Show root */
  2855. }
  2856.  
  2857. /*
  2858. ** Huffman tree built...compress the plaintext
  2859. */
  2860. bitoffset=0L;                           /* Initialize bit offset */
  2861. for(i=0;i<arraysize;i++)
  2862. {
  2863.         c=(int)plaintext[i];                 /* Fetch character */
  2864.         /*
  2865.         ** Build a bit string for byte c
  2866.         */
  2867.         bitstringlen=0;
  2868.         while(hufftree[c].parent!=-2)
  2869.         {       if(hufftree[hufftree[c].parent].left==c)
  2870.                         bitstring[bitstringlen]='0';
  2871.                 else
  2872.                         bitstring[bitstringlen]='1';
  2873.                 c=hufftree[c].parent;
  2874.                 bitstringlen++;
  2875.         }
  2876.  
  2877.         /*
  2878.         ** Step backwards through the bit string, setting
  2879.         ** bits in the compressed array as you go.
  2880.         */
  2881.         while(bitstringlen--)
  2882.         {       SetCompBit((u8 *)comparray,(u32)bitoffset,bitstring[bitstringlen]);
  2883.                 bitoffset++;
  2884.         }
  2885. }
  2886.  
  2887. /*
  2888. ** Compression done.  Perform de-compression.
  2889. */
  2890. maxbitoffset=bitoffset;
  2891. bitoffset=0;
  2892. textoffset=0;
  2893. do {
  2894.         i=root;
  2895.         while(hufftree[i].left!=-1)
  2896.         {       if(GetCompBit((u8 *)comparray,(u32)bitoffset)==0)
  2897.                         i=hufftree[i].left;
  2898.                 else
  2899.                         i=hufftree[i].right;
  2900.                 bitoffset++;
  2901.         }
  2902.         decomparray[textoffset]=hufftree[i].c;
  2903.  
  2904. #ifdef DEBUG
  2905.         if(hufftree[i].c != plaintext[textoffset])
  2906.         {
  2907.                 /* Show error */
  2908.                 printf("Error at textoffset %d\n",textoffset);
  2909.         }
  2910. #endif
  2911.         textoffset++;
  2912. } while(bitoffset<maxbitoffset);
  2913.  
  2914. }       /* End the big while(nloops--) from above */
  2915.  
  2916. /*
  2917. ** All done
  2918. */
  2919. return(StopStopwatch(elapsed));
  2920. }
  2921.  
  2922. /***************
  2923. ** SetCompBit **
  2924. ****************
  2925. ** Set a bit in the compression array.  The value of the
  2926. ** bit is set according to char bitchar.
  2927. */
  2928. static void SetCompBit(u8 *comparray,
  2929.                 u32 bitoffset,
  2930.                 char bitchar)
  2931. {
  2932. u32 byteoffset;
  2933. int bitnumb;
  2934.  
  2935. /*
  2936. ** First calculate which element in the comparray to
  2937. ** alter. and the bitnumber.
  2938. */
  2939. byteoffset=bitoffset>>3;
  2940. bitnumb=bitoffset % 8;
  2941.  
  2942. /*
  2943. ** Set or clear
  2944. */
  2945. if(bitchar=='1')
  2946.         comparray[byteoffset]|=(1<<bitnumb);
  2947. else
  2948.         comparray[byteoffset]&=~(1<<bitnumb);
  2949.  
  2950. return;
  2951. }
  2952.  
  2953. /***************
  2954. ** GetCompBit **
  2955. ****************
  2956. ** Return the bit value of a bit in the comparession array.
  2957. ** Returns 0 if the bit is clear, nonzero otherwise.
  2958. */
  2959. static int GetCompBit(u8 *comparray,
  2960.                 u32 bitoffset)
  2961. {
  2962. u32 byteoffset;
  2963. int bitnumb;
  2964.  
  2965. /*
  2966. ** Calculate byte offset and bit number.
  2967. */
  2968. byteoffset=bitoffset>>3;
  2969. bitnumb=bitoffset % 8;
  2970.  
  2971. /*
  2972. ** Fetch
  2973. */
  2974. return((1<<bitnumb) & comparray[byteoffset] );
  2975. }
  2976.  
  2977. /********************************
  2978. ** BACK PROPAGATION NEURAL NET **
  2979. *********************************
  2980. ** This code is a modified version of the code
  2981. ** that was submitted to BYTE Magazine by
  2982. ** Maureen Caudill.  It accomanied an article
  2983. ** that I CANNOT NOW RECALL.
  2984. ** The author's original heading/comment was
  2985. ** as follows:
  2986. **
  2987. **  Backpropagation Network
  2988. **  Written by Maureen Caudill
  2989. **  in Think C 4.0 on a Macintosh
  2990. **
  2991. **  (c) Maureen Caudill 1988-1991
  2992. **  This network will accept 5x7 input patterns
  2993. **  and produce 8 bit output patterns.
  2994. **  The source code may be copied or modified without restriction,
  2995. **  but no fee may be charged for its use.
  2996. **
  2997. ** ++++++++++++++
  2998. ** I have modified the code so that it will work
  2999. ** on systems other than a Macintosh -- RG
  3000. */
  3001.  
  3002. /***********
  3003. ** DoNNet **
  3004. ************
  3005. ** Perform the neural net benchmark.
  3006. ** Note that this benchmark is one of the few that
  3007. ** requires an input file.  That file is "NNET.DAT" and
  3008. ** should be on the local directory (from which the
  3009. ** benchmark program in launched).
  3010. */
  3011. void DoNNET(void)
  3012. {
  3013. NNetStruct *locnnetstruct;      /* Local ptr to global data */
  3014. char *errorcontext;
  3015. int systemerror;
  3016. ulong accumtime;
  3017. double iterations;
  3018.  
  3019. /*
  3020. ** Link to global data
  3021. */
  3022. locnnetstruct=&global_nnetstruct;
  3023.  
  3024. /*
  3025. ** Set error context
  3026. */
  3027. errorcontext="CPU:NNET";
  3028.  
  3029. /*
  3030. ** Init random number generator.
  3031. ** NOTE: It is important that the random number generator
  3032. **  be re-initialized for every pass through this test.
  3033. **  The NNET algorithm uses the random number generator
  3034. **  to initialize the net.  Results are sensitive to
  3035. **  the initial neural net state.
  3036. */
  3037. randnum(3L);
  3038.  
  3039. /*
  3040. ** Read in the input and output patterns.  We'll do this
  3041. ** only once here at the beginning.  These values don't
  3042. ** change once loaded.
  3043. */
  3044. if(read_data_file()!=0)
  3045.    ErrorExit();
  3046.  
  3047.  
  3048. /*
  3049. ** See if we need to perform self adjustment loop.
  3050. */
  3051. if(locnnetstruct->adjust==0)
  3052. {
  3053.         /*
  3054.         ** Do self-adjustment.  This involves initializing the
  3055.         ** # of loops and increasing the loop count until we
  3056.         ** get a number of loops that we can use.
  3057.         */
  3058.         for(locnnetstruct->loops=1L;
  3059.           locnnetstruct->loops<MAXNNETLOOPS;
  3060.           locnnetstruct->loops++)
  3061.           {     randnum(3L);
  3062.                 if(DoNNetIteration(locnnetstruct->loops)
  3063.                         >global_min_ticks) break;
  3064.           }
  3065. }
  3066.  
  3067. /*
  3068. ** All's well if we get here.  Do the test.
  3069. */
  3070. accumtime=0L;             
  3071. iterations=(double)0.0;
  3072.  
  3073. do {
  3074.         randnum(3L);    /* Gotta do this for Neural Net */
  3075.         accumtime+=DoNNetIteration(locnnetstruct->loops);
  3076.         iterations+=(double)locnnetstruct->loops;
  3077. } while(TicksToSecs(accumtime)<locnnetstruct->request_secs);
  3078.  
  3079. /*
  3080. ** Clean up, calculate results, and go home.  Be sure to
  3081. ** show that we don't have to rerun adjustment code.
  3082. */
  3083. locnnetstruct->iterspersec=iterations / TicksToFracSecs(accumtime);
  3084.  
  3085. if(locnnetstruct->adjust==0)
  3086.         locnnetstruct->adjust=1;
  3087.  
  3088.  
  3089. return;
  3090. }
  3091.  
  3092. /********************
  3093. ** DoNNetIteration **
  3094. *********************
  3095. ** Do a single iteration of the neural net benchmark.
  3096. ** By iteration, we mean a "learning" pass.
  3097. */
  3098. static ulong DoNNetIteration(ulong nloops)
  3099. {
  3100. ulong elapsed;          /* Elapsed time */
  3101. int patt;
  3102.  
  3103. /*
  3104. ** Run nloops learning cycles.  Notice that, counted with
  3105. ** the learning cycle is the weight randomization and
  3106. ** zeroing of changes.  This should reduce clock jitter,
  3107. ** since we don't have to stop and start the clock for
  3108. ** each iteration.
  3109. */
  3110. elapsed=StartStopwatch();
  3111. while(nloops--)
  3112. {
  3113.         randomize_wts();
  3114.         zero_changes();
  3115.         iteration_count=1;
  3116.         learned = F;
  3117.         numpasses = 0;
  3118.         while (learned == F)
  3119.         {
  3120.                 for (patt=0; patt<numpats; patt++)
  3121.                 {
  3122.                         worst_error = 0.0;      /* reset this every pass through data */
  3123.                         move_wt_changes();      /* move last pass's wt changes to momentum array */
  3124.                         do_forward_pass(patt);
  3125.                         do_back_pass(patt);
  3126.                         iteration_count++;
  3127.                 }
  3128.                 numpasses ++;
  3129.                 learned = check_out_error();
  3130.         }
  3131. #ifdef DEBUG
  3132. printf("Learned in %d passes\n",numpasses);
  3133. #endif
  3134. }
  3135. return(StopStopwatch(elapsed));
  3136. }
  3137.  
  3138. /*************************
  3139. ** do_mid_forward(patt) **
  3140. **************************
  3141. ** Process the middle layer's forward pass
  3142. ** The activation of middle layer's neurode is the weighted
  3143. ** sum of the inputs from the input pattern, with sigmoid
  3144. ** function applied to the inputs.
  3145. **/
  3146. static void  do_mid_forward(int patt)
  3147. {
  3148. double  sum;
  3149. int     neurode, i;
  3150.  
  3151. for (neurode=0;neurode<MID_SIZE; neurode++)
  3152. {
  3153.         sum = 0.0;
  3154.         for (i=0; i<IN_SIZE; i++)
  3155.         {       /* compute weighted sum of input signals */
  3156.                 sum += mid_wts[neurode][i]*in_pats[patt][i];
  3157.         }
  3158.         /*
  3159.         ** apply sigmoid function f(x) = 1/(1+exp(-x)) to weighted sum
  3160.         */
  3161.         sum = 1.0/(1.0+exp(-sum));
  3162.         mid_out[neurode] = sum;
  3163. }
  3164. return;
  3165. }
  3166.  
  3167. /*********************
  3168. ** do_out_forward() **
  3169. **********************
  3170. ** process the forward pass through the output layer
  3171. ** The activation of the output layer is the weighted sum of
  3172. ** the inputs (outputs from middle layer), modified by the
  3173. ** sigmoid function.
  3174. **/
  3175. static void  do_out_forward()
  3176. {
  3177. double sum;
  3178. int neurode, i;
  3179.  
  3180. for (neurode=0; neurode<OUT_SIZE; neurode++)
  3181. {
  3182.         sum = 0.0;
  3183.         for (i=0; i<MID_SIZE; i++)
  3184.         {       /*
  3185.                 ** compute weighted sum of input signals
  3186.                 ** from middle layer
  3187.                 */
  3188.                 sum += out_wts[neurode][i]*mid_out[i];
  3189.         }
  3190.         /*
  3191.         ** Apply f(x) = 1/(1+exp(-x)) to weighted input
  3192.         */
  3193.         sum = 1.0/(1.0+exp(-sum));
  3194.         out_out[neurode] = sum;
  3195. }
  3196. return;
  3197. }
  3198.  
  3199. /*************************
  3200. ** display_output(patt) **
  3201. **************************
  3202. ** Display the actual output vs. the desired output of the
  3203. ** network.
  3204. ** Once the training is complete, and the "learned" flag set
  3205. ** to TRUE, then display_output sends its output to both
  3206. ** the screen and to a text output file.
  3207. **
  3208. ** NOTE: This routine has been disabled in the benchmark
  3209. ** version. -- RG
  3210. **/
  3211. /*
  3212. void  display_output(int patt)
  3213. {
  3214. int             i;
  3215.  
  3216.         fprintf(outfile,"\n Iteration # %d",iteration_count);
  3217.         fprintf(outfile,"\n Desired Output:  ");
  3218.  
  3219.         for (i=0; i<OUT_SIZE; i++)
  3220.         {
  3221.                 fprintf(outfile,"%6.3f  ",out_pats[patt][i]);
  3222.         }
  3223.         fprintf(outfile,"\n Actual Output:   ");
  3224.  
  3225.         for (i=0; i<OUT_SIZE; i++)
  3226.         {
  3227.                 fprintf(outfile,"%6.3f  ",out_out[i]);
  3228.         }
  3229.         fprintf(outfile,"\n");
  3230.         return;
  3231. }
  3232. */
  3233.  
  3234. /**********************
  3235. ** do_forward_pass() **
  3236. ***********************
  3237. ** control function for the forward pass through the network
  3238. ** NOTE: I have disabled the call to display_output() in
  3239. **  the benchmark version -- RG.
  3240. **/
  3241. static void  do_forward_pass(int patt)
  3242. {
  3243. do_mid_forward(patt);   /* process forward pass, middle layer */
  3244. do_out_forward();       /* process forward pass, output layer */
  3245. /* display_output(patt);        ** display results of forward pass */
  3246. return;
  3247. }
  3248.  
  3249. /***********************
  3250. ** do_out_error(patt) **
  3251. ************************
  3252. ** Compute the error for the output layer neurodes.
  3253. ** This is simply Desired - Actual.
  3254. **/
  3255. static void do_out_error(int patt)
  3256. {
  3257. int neurode;
  3258. double error,tot_error, sum;
  3259.  
  3260. tot_error = 0.0;
  3261. sum = 0.0;
  3262. for (neurode=0; neurode<OUT_SIZE; neurode++)
  3263. {
  3264.         out_error[neurode] = out_pats[patt][neurode] - out_out[neurode];
  3265.         /*
  3266.         ** while we're here, also compute magnitude
  3267.         ** of total error and worst error in this pass.
  3268.         ** We use these to decide if we are done yet.
  3269.         */
  3270.         error = out_error[neurode];
  3271.         if (error <0.0)
  3272.         {
  3273.                 sum += -error;
  3274.                 if (-error > tot_error)
  3275.                         tot_error = -error; /* worst error this pattern */
  3276.         }
  3277.         else
  3278.         {
  3279.                 sum += error;
  3280.                 if (error > tot_error)
  3281.                         tot_error = error; /* worst error this pattern */
  3282.         }
  3283. }
  3284. avg_out_error[patt] = sum/OUT_SIZE;
  3285. tot_out_error[patt] = tot_error;
  3286. return;
  3287. }
  3288.  
  3289. /***********************
  3290. ** worst_pass_error() **
  3291. ************************
  3292. ** Find the worst and average error in the pass and save it
  3293. **/
  3294. static void  worst_pass_error()
  3295. {
  3296. double error,sum;
  3297.  
  3298. int i;
  3299.  
  3300. error = 0.0;
  3301. sum = 0.0;
  3302. for (i=0; i<numpats; i++)
  3303. {
  3304.         if (tot_out_error[i] > error) error = tot_out_error[i];
  3305.         sum += avg_out_error[i];
  3306. }
  3307. worst_error = error;
  3308. average_error = sum/numpats;
  3309. return;
  3310. }
  3311.  
  3312. /*******************
  3313. ** do_mid_error() **
  3314. ********************
  3315. ** Compute the error for the middle layer neurodes
  3316. ** This is based on the output errors computed above.
  3317. ** Note that the derivative of the sigmoid f(x) is
  3318. **        f'(x) = f(x)(1 - f(x))
  3319. ** Recall that f(x) is merely the output of the middle
  3320. ** layer neurode on the forward pass.
  3321. **/
  3322. static void do_mid_error()
  3323. {
  3324. double sum;
  3325. int neurode, i;
  3326.  
  3327. for (neurode=0; neurode<MID_SIZE; neurode++)
  3328. {
  3329.         sum = 0.0;
  3330.         for (i=0; i<OUT_SIZE; i++)
  3331.                 sum += out_wts[i][neurode]*out_error[i];
  3332.  
  3333.         /*
  3334.         ** apply the derivative of the sigmoid here
  3335.         ** Because of the choice of sigmoid f(I), the derivative
  3336.         ** of the sigmoid is f'(I) = f(I)(1 - f(I))
  3337.         */
  3338.         mid_error[neurode] = mid_out[neurode]*(1-mid_out[neurode])*sum;
  3339. }
  3340. return;
  3341. }
  3342.  
  3343. /*********************
  3344. ** adjust_out_wts() **
  3345. **********************
  3346. ** Adjust the weights of the output layer.  The error for
  3347. ** the output layer has been previously propagated back to
  3348. ** the middle layer.
  3349. ** Use the Delta Rule with momentum term to adjust the weights.
  3350. **/
  3351. static void adjust_out_wts()
  3352. {
  3353. int weight, neurode;
  3354. double learn,delta,alph;
  3355.  
  3356. learn = BETA;
  3357. alph  = ALPHA;
  3358. for (neurode=0; neurode<OUT_SIZE; neurode++)
  3359. {
  3360.         for (weight=0; weight<MID_SIZE; weight++)
  3361.         {
  3362.                 /* standard delta rule */
  3363.                 delta = learn * out_error[neurode] * mid_out[weight];
  3364.  
  3365.                 /* now the momentum term */
  3366.                 delta += alph * out_wt_change[neurode][weight];
  3367.                 out_wts[neurode][weight] += delta;
  3368.  
  3369.                 /* keep track of this pass's cum wt changes for next pass's momentum */
  3370.                 out_wt_cum_change[neurode][weight] += delta;
  3371.         }
  3372. }
  3373. return;
  3374. }
  3375.  
  3376. /*************************
  3377. ** adjust_mid_wts(patt) **
  3378. **************************
  3379. ** Adjust the middle layer weights using the previously computed
  3380. ** errors.
  3381. ** We use the Generalized Delta Rule with momentum term
  3382. **/
  3383. static void adjust_mid_wts(int patt)
  3384. {
  3385. int weight, neurode;
  3386. double learn,alph,delta;
  3387.  
  3388. learn = BETA;
  3389. alph  = ALPHA;
  3390. for (neurode=0; neurode<MID_SIZE; neurode++)
  3391. {
  3392.         for (weight=0; weight<IN_SIZE; weight++)
  3393.         {
  3394.                 /* first the basic delta rule */
  3395.                 delta = learn * mid_error[neurode] * in_pats[patt][weight];
  3396.  
  3397.                 /* with the momentum term */
  3398.                 delta += alph * mid_wt_change[neurode][weight];
  3399.                 mid_wts[neurode][weight] += delta;
  3400.  
  3401.                 /* keep track of this pass's cum wt changes for next pass's momentum */
  3402.                 mid_wt_cum_change[neurode][weight] += delta;
  3403.         }
  3404. }
  3405. return;
  3406. }
  3407.  
  3408. /*******************
  3409. ** do_back_pass() **
  3410. ********************
  3411. ** Process the backward propagation of error through network.
  3412. **/
  3413. void  do_back_pass(int patt)
  3414. {
  3415.  
  3416. do_out_error(patt);
  3417. do_mid_error();
  3418. adjust_out_wts();
  3419. adjust_mid_wts(patt);
  3420.  
  3421. return;
  3422. }
  3423.  
  3424.  
  3425. /**********************
  3426. ** move_wt_changes() **
  3427. ***********************
  3428. ** Move the weight changes accumulated last pass into the wt-change
  3429. ** array for use by the momentum term in this pass. Also zero out
  3430. ** the accumulating arrays after the move.
  3431. **/
  3432. static void move_wt_changes()
  3433. {
  3434. int i,j;
  3435.  
  3436. for (i = 0; i<MID_SIZE; i++)
  3437.         for (j = 0; j<IN_SIZE; j++)
  3438.         {
  3439.                 mid_wt_change[i][j] = mid_wt_cum_change[i][j];
  3440.                 /*
  3441.                 ** Zero it out for next pass accumulation.
  3442.                 */
  3443.                 mid_wt_cum_change[i][j] = 0.0;
  3444.         }
  3445.  
  3446. for (i = 0; i<OUT_SIZE; i++)
  3447.         for (j=0; j<MID_SIZE; j++)
  3448.         {
  3449.                 out_wt_change[i][j] = out_wt_cum_change[i][j];
  3450.                 out_wt_cum_change[i][j] = 0.0;
  3451.         }
  3452.  
  3453. return;
  3454. }
  3455.  
  3456. /**********************
  3457. ** check_out_error() **
  3458. ***********************
  3459. ** Check to see if the error in the output layer is below
  3460. ** MARGIN*OUT_SIZE for all output patterns.  If so, then
  3461. ** assume the network has learned acceptably well.  This
  3462. ** is simply an arbitrary measure of how well the network
  3463. ** has learned -- many other standards are possible.
  3464. **/
  3465. static int check_out_error()
  3466. {
  3467. int result,i,error;
  3468.  
  3469. result  = T;
  3470. error   = F;
  3471. worst_pass_error();     /* identify the worst error in this pass */
  3472.  
  3473. /*
  3474. #ifdef DEBUG
  3475. printf("\n Iteration # %d",iteration_count);
  3476. #endif
  3477. */
  3478. for (i=0; i<numpats; i++)
  3479. {
  3480. /*      printf("\n Error pattern %d:   Worst: %8.3f; Average: %8.3f",
  3481.           i+1,tot_out_error[i], avg_out_error[i]);
  3482.         fprintf(outfile,
  3483.          "\n Error pattern %d:   Worst: %8.3f; Average: %8.3f",
  3484.          i+1,tot_out_error[i]);
  3485. */
  3486.  
  3487.         if (worst_error >= STOP) result = F;
  3488.         if (tot_out_error[i] >= 16.0) error = T;
  3489. }
  3490.  
  3491. if (error == T) result = ERR;
  3492.  
  3493.  
  3494. #ifdef DEBUG
  3495. /* printf("\n Error this pass thru data:   Worst: %8.3f; Average: %8.3f",
  3496.  worst_error,average_error);
  3497. */
  3498. /* fprintf(outfile,
  3499.  "\n Error this pass thru data:   Worst: %8.3f; Average: %8.3f",
  3500.   worst_error, average_error); */
  3501. #endif
  3502.  
  3503. return(result);
  3504. }
  3505.  
  3506.  
  3507. /*******************
  3508. ** zero_changes() **
  3509. ********************
  3510. ** Zero out all the wt change arrays
  3511. **/
  3512. static void zero_changes()
  3513. {
  3514. int i,j;
  3515.  
  3516. for (i = 0; i<MID_SIZE; i++)
  3517. {
  3518.         for (j=0; j<IN_SIZE; j++)
  3519.         {
  3520.                 mid_wt_change[i][j] = 0.0;
  3521.                 mid_wt_cum_change[i][j] = 0.0;
  3522.         }
  3523. }
  3524.  
  3525. for (i = 0; i< OUT_SIZE; i++)
  3526. {
  3527.         for (j=0; j<MID_SIZE; j++)
  3528.         {
  3529.                 out_wt_change[i][j] = 0.0;
  3530.                 out_wt_cum_change[i][j] = 0.0;
  3531.         }
  3532. }
  3533. return;
  3534. }
  3535.  
  3536.  
  3537. /********************
  3538. ** randomize_wts() **
  3539. *********************
  3540. ** Intialize the weights in the middle and output layers to
  3541. ** random values between -0.25..+0.25
  3542. ** Function rand() returns a value between 0 and 32767.
  3543. **
  3544. ** NOTE: Had to make alterations to how the random numbers were
  3545. ** created.  -- RG.
  3546. **/
  3547. static void randomize_wts()
  3548. {
  3549. int neurode,i;
  3550. double value;
  3551.  
  3552. /*
  3553. ** Following not used int benchmark version -- RG
  3554. **
  3555. **        printf("\n Please enter a random number seed (1..32767):  ");
  3556. **        scanf("%d", &i);
  3557. **        srand(i);
  3558. */
  3559. for (neurode = 0; neurode<MID_SIZE; neurode++)
  3560. {
  3561.         for(i=0; i<IN_SIZE; i++)
  3562.         {
  3563.                 value=(double)abs_randwc(100000L);
  3564.                 value=value/(double)100000.0 - (double) 0.5;
  3565.                 mid_wts[neurode][i] = value/2;
  3566.         }
  3567. }
  3568.  
  3569. for (neurode=0; neurode<OUT_SIZE; neurode++)
  3570. {
  3571.         for(i=0; i<MID_SIZE; i++)
  3572.         {
  3573.                 value=(double)abs_randwc(100000L);
  3574.                 value=value/(double)10000.0 - (double) 0.5;
  3575.                 out_wts[neurode][i] = value/2;
  3576.         }
  3577. }
  3578. return;
  3579. }
  3580.  
  3581.  
  3582. /*********************
  3583. ** read_data_file() **
  3584. **********************
  3585. ** Read in the input data file and store the patterns in
  3586. ** in_pats and out_pats.
  3587. ** The format for the data file is as follows:
  3588. **
  3589. ** line#   data expected
  3590. ** -----   ------------------------------
  3591. ** 1               In-X-size,in-y-size,out-size
  3592. ** 2               number of patterns in file
  3593. ** 3               1st X row of 1st input pattern
  3594. ** 4..             following rows of 1st input pattern pattern
  3595. **                 in-x+2  y-out pattern
  3596. **                                 1st X row of 2nd pattern
  3597. **                 etc.
  3598. **
  3599. ** Each row of data is separated by commas or spaces.
  3600. ** The data is expected to be ascii text corresponding to
  3601. ** either a +1 or a 0.
  3602. **
  3603. ** Sample input for a 1-pattern file (The comments to the
  3604. ** right may NOT be in the file unless more sophisticated
  3605. ** parsing of the input is done.):
  3606. **
  3607. ** 5,7,8                      input is 5x7 grid, output is 8 bits
  3608. ** 1                          one pattern in file
  3609. ** 0,1,1,1,0                  beginning of pattern for "O"
  3610. ** 1,0,0,0,1
  3611. ** 1,0,0,0,1
  3612. ** 1,0,0,0,1
  3613. ** 1,0,0,0,1
  3614. ** 1,0,0,0,0
  3615. ** 0,1,1,1,0
  3616. ** 0,1,0,0,1,1,1,1            ASCII code for "O" -- 0100 1111
  3617. **
  3618. ** Clearly, this simple scheme can be expanded or enhanced
  3619. ** any way you like.
  3620. **
  3621. ** Returns -1 if any file error occurred, otherwise 0.
  3622. **/
  3623. static int read_data_file()
  3624. {
  3625. FILE *infile;
  3626.  
  3627. int xinsize,yinsize,youtsize;
  3628. int patt, element, i, row;
  3629. int vals_read;
  3630. int val1,val2,val3,val4,val5,val6,val7,val8;
  3631.  
  3632. /* printf("\n Opening and retrieving data from file."); */
  3633.  
  3634. infile = fopen(inpath, "r");
  3635. if (infile == NULL)
  3636. {
  3637.         printf("\n CPU:NNET--error in opening file!");
  3638.         return -1 ;
  3639. }
  3640. vals_read =fscanf(infile,"%d  %d  %d",&xinsize,&yinsize,&youtsize);
  3641. if (vals_read != 3)
  3642. {
  3643.         printf("\n CPU:NNET -- Should read 3 items in line one; did read %d",vals_read);
  3644.         return -1;
  3645. }
  3646. vals_read=fscanf(infile,"%d",&numpats);
  3647. if (vals_read !=1)
  3648. {
  3649.         printf("\n CPU:NNET -- Should read 1 item in line 2; did read &d",vals_read);
  3650.         return -1;
  3651. }
  3652. if (numpats > MAXPATS)
  3653.         numpats = MAXPATS;
  3654.  
  3655. for (patt=0; patt<numpats; patt++)
  3656. {
  3657.         element = 0;
  3658.         for (row = 0; row<yinsize; row++)
  3659.         {
  3660.                 vals_read = fscanf(infile,"%d  %d  %d  %d  %d",
  3661.                         &val1, &val2, &val3, &val4, &val5);
  3662.                 if (vals_read != 5)
  3663.                 {
  3664.                         printf ("\n CPU:NNET -- failure in reading input!");
  3665.                         return -1;
  3666.                 }
  3667.                 element=row*xinsize;
  3668.  
  3669.                 in_pats[patt][element] = (double) val1; element++;
  3670.                 in_pats[patt][element] = (double) val2; element++;
  3671.                 in_pats[patt][element] = (double) val3; element++;
  3672.                 in_pats[patt][element] = (double) val4; element++;
  3673.                 in_pats[patt][element] = (double) val5; element++;
  3674.         }
  3675.         for (i=0;i<IN_SIZE; i++)
  3676.         {
  3677.                 if (in_pats[patt][i] >= 0.9)
  3678.                         in_pats[patt][i] = 0.9;
  3679.                 if (in_pats[patt][i] <= 0.1)
  3680.                         in_pats[patt][i] = 0.1;
  3681.         }
  3682.         element = 0;
  3683.         vals_read = fscanf(infile,"%d  %d  %d  %d  %d  %d  %d  %d",
  3684.                 &val1, &val2, &val3, &val4, &val5, &val6, &val7, &val8);
  3685.  
  3686.         out_pats[patt][element] = (double) val1; element++;
  3687.         out_pats[patt][element] = (double) val2; element++;
  3688.         out_pats[patt][element] = (double) val3; element++;
  3689.         out_pats[patt][element] = (double) val4; element++;
  3690.         out_pats[patt][element] = (double) val5; element++;
  3691.         out_pats[patt][element] = (double) val6; element++;
  3692.         out_pats[patt][element] = (double) val7; element++;
  3693.         out_pats[patt][element] = (double) val8; element++;
  3694. }
  3695.  
  3696. /* printf("\n Closing the input file now. "); */
  3697.  
  3698. fclose(infile);
  3699. return(0);
  3700. }
  3701.  
  3702. /*********************
  3703. ** initialize_net() **
  3704. **********************
  3705. ** Do all the initialization stuff before beginning
  3706. */
  3707. static int initialize_net()
  3708. {
  3709. int err_code;
  3710.  
  3711. randomize_wts();
  3712. zero_changes();
  3713. err_code = read_data_file();
  3714. iteration_count = 1;
  3715. return(err_code);
  3716. }
  3717.  
  3718. /**********************
  3719. ** display_mid_wts() **
  3720. ***********************
  3721. ** Display the weights on the middle layer neurodes
  3722. ** NOTE: This routine is not used in the benchmark
  3723. **  test -- RG
  3724. **/
  3725. /* static void display_mid_wts()
  3726. {
  3727. int             neurode, weight, row, col;
  3728.  
  3729. fprintf(outfile,"\n Weights of Middle Layer neurodes:");
  3730.  
  3731. for (neurode=0; neurode<MID_SIZE; neurode++)
  3732. {
  3733.         fprintf(outfile,"\n  Mid Neurode # %d",neurode);
  3734.         for (row=0; row<IN_Y_SIZE; row++)
  3735.         {
  3736.                 fprintf(outfile,"\n ");
  3737.                 for (col=0; col<IN_X_SIZE; col++)
  3738.                 {
  3739.                         weight = IN_X_SIZE * row + col;
  3740.                         fprintf(outfile," %8.3f ", mid_wts[neurode][weight]);
  3741.                 }
  3742.         }
  3743. }
  3744. return;
  3745. }
  3746. */
  3747. /**********************
  3748. ** display_out_wts() **
  3749. ***********************
  3750. ** Display the weights on the output layer neurodes
  3751. ** NOTE: This code is not used in the benchmark
  3752. **  test -- RG
  3753. */
  3754. /* void  display_out_wts()
  3755. {
  3756. int             neurode, weight;
  3757.  
  3758.         fprintf(outfile,"\n Weights of Output Layer neurodes:");
  3759.  
  3760.         for (neurode=0; neurode<OUT_SIZE; neurode++)
  3761.         {
  3762.                 fprintf(outfile,"\n  Out Neurode # %d \n",neurode);
  3763.                 for (weight=0; weight<MID_SIZE; weight++)
  3764.                 {
  3765.                         fprintf(outfile," %8.3f ", out_wts[neurode][weight]);
  3766.                 }
  3767.         }
  3768.         return;
  3769. }
  3770. */
  3771.  
  3772. /***********************
  3773. **  LU DECOMPOSITION  **
  3774. ** (Linear Equations) **
  3775. ************************
  3776. ** These routines come from "Numerical Recipes in Pascal".
  3777. ** Note that, as in the assignment algorithm, though we
  3778. ** separately define LUARRAYROWS and LUARRAYCOLS, the two
  3779. ** must be the same value (this routine depends on a square
  3780. ** matrix).
  3781. */
  3782.  
  3783. /*********
  3784. ** DoLU **
  3785. **********
  3786. ** Perform the LU decomposition benchmark.
  3787. */
  3788. void DoLU(void)
  3789. {
  3790. LUStruct *loclustruct;  /* Local pointer to global data */
  3791. char *errorcontext;
  3792. int systemerror;
  3793. double *a;
  3794. double *b;
  3795. double *abase;
  3796. double *bbase;
  3797. LUdblptr ptra;
  3798. int n;
  3799. int i;
  3800. ulong accumtime;
  3801. double iterations;
  3802.  
  3803. /*
  3804. ** Link to global data
  3805. */
  3806. loclustruct=&global_lustruct;
  3807.  
  3808. /*
  3809. ** Set error context.
  3810. */
  3811. errorcontext="FPU:LU";
  3812.  
  3813. /*
  3814. ** Our first step is to build a "solvable" problem.  This
  3815. ** will become the "seed" set that all others will be
  3816. ** derived from. (I.E., we'll simply copy these arrays
  3817. ** into the others.
  3818. */
  3819. a=(double *)AllocateMemory(sizeof(double) * LUARRAYCOLS * LUARRAYROWS,
  3820.                 &systemerror);
  3821. b=(double *)AllocateMemory(sizeof(double) * LUARRAYROWS,
  3822.                 &systemerror);
  3823. n=LUARRAYROWS;
  3824.  
  3825. /*
  3826. ** Build a problem to be solved.
  3827. */
  3828. ptra.ptrs.p=a;                  /* Gotta coerce linear array to 2D array */
  3829. build_problem(*ptra.ptrs.ap,n,b);
  3830.  
  3831. /*
  3832. ** Now that we have a problem built, see if we need to do
  3833. ** auto-adjust.  If so, repeatedly call the DoLUIteration routine,
  3834. ** increasing the number of solutions per iteration as you go.
  3835. */
  3836. if(loclustruct->adjust==0)
  3837. {
  3838.         loclustruct->numarrays=0;
  3839.         for(i=1;i<=MAXLUARRAYS;i++)
  3840.         {
  3841.                 abase=(double *)AllocateMemory(sizeof(double) *
  3842.                         LUARRAYCOLS*LUARRAYROWS*(i+1),&systemerror);
  3843.                 if(systemerror)
  3844.                 {       ReportError(errorcontext,systemerror);
  3845.                         LUFreeMem(a,b,(double *)NULL,(double *)NULL);
  3846.                         ErrorExit();
  3847.                 }
  3848.                 bbase=(double *)AllocateMemory(sizeof(double) *
  3849.                         LUARRAYROWS*(i+1),&systemerror);
  3850.                 if(systemerror)
  3851.                 {       ReportError(errorcontext,systemerror);
  3852.                         LUFreeMem(a,b,abase,(double *)NULL);
  3853.                         ErrorExit();
  3854.                 }       
  3855.                 if(DoLUIteration(a,b,abase,bbase,i)>global_min_ticks)
  3856.                 {       loclustruct->numarrays=i;
  3857.                         break;
  3858.                 }
  3859.                 /*
  3860.                 ** Not enough arrays...free them all and try again
  3861.                 */
  3862.                 FreeMemory((farvoid *)abase,&systemerror);
  3863.                 FreeMemory((farvoid *)bbase,&systemerror);
  3864.         }
  3865.         /*
  3866.         ** Were we able to do it?
  3867.         */
  3868.         if(loclustruct->numarrays==0)
  3869.         {       printf("FPU:LU -- Array limit reached\n");
  3870.                 LUFreeMem(a,b,abase,bbase);
  3871.                 ErrorExit();
  3872.         }
  3873. }
  3874. else
  3875. {       /*
  3876.         ** Don't need to adjust -- just allocate the proper
  3877.         ** number of arrays and proceed.
  3878.         */
  3879.         abase=(double *)AllocateMemory(sizeof(double) *
  3880.                 LUARRAYCOLS*LUARRAYROWS*loclustruct->numarrays,
  3881.                 &systemerror);
  3882.         if(systemerror)
  3883.         {       ReportError(errorcontext,systemerror);
  3884.                 LUFreeMem(a,b,(double *)NULL,(double *)NULL);
  3885.                 ErrorExit();
  3886.         }
  3887.         bbase=(double *)AllocateMemory(sizeof(double) *
  3888.                 LUARRAYROWS*loclustruct->numarrays,&systemerror);
  3889.         if(systemerror)
  3890.         {
  3891.                 ReportError(errorcontext,systemerror);
  3892.                 LUFreeMem(a,b,abase,(double *)NULL);
  3893.                 ErrorExit();
  3894.         }
  3895. }
  3896. /*
  3897. ** All's well if we get here.  Do the test.
  3898. */
  3899. accumtime=0L;
  3900. iterations=(double)0.0;
  3901.  
  3902. do {
  3903.         accumtime+=DoLUIteration(a,b,abase,bbase,
  3904.                 loclustruct->numarrays);
  3905.         iterations+=(double)loclustruct->numarrays;
  3906. } while(TicksToSecs(accumtime)<loclustruct->request_secs);
  3907.  
  3908. /*
  3909. ** Clean up, calculate results, and go home.  Be sure to
  3910. ** show that we don't have to rerun adjustment code.
  3911. */
  3912. loclustruct->iterspersec=iterations / TicksToFracSecs(accumtime);
  3913.  
  3914. if(loclustruct->adjust==0)
  3915.         loclustruct->adjust=1;
  3916.  
  3917. LUFreeMem(a,b,abase,bbase);
  3918. return;
  3919. }
  3920.  
  3921. /**************
  3922. ** LUFreeMem **
  3923. ***************
  3924. ** Release memory associated with LU benchmark.
  3925. */
  3926. static void LUFreeMem(double *a, double *b,
  3927.                         double *abase,double *bbase)
  3928. {
  3929. int systemerror;
  3930.  
  3931. FreeMemory((farvoid *)a,&systemerror);
  3932. FreeMemory((farvoid *)b,&systemerror);
  3933.  
  3934. if(abase!=(double *)NULL) FreeMemory((farvoid *)abase,&systemerror);
  3935. if(bbase!=(double *)NULL) FreeMemory((farvoid *)bbase,&systemerror);
  3936. return;
  3937. }
  3938.  
  3939. /******************
  3940. ** DoLUIteration **
  3941. *******************
  3942. ** Perform an iteration of the LU decomposition benchmark.
  3943. ** An iteration refers to the repeated solution of several
  3944. ** identical matrices.
  3945. */
  3946. static ulong DoLUIteration(double *a,double *b,
  3947.                 double *abase, double *bbase,
  3948.                 ulong numarrays)
  3949. {
  3950. double *locabase;
  3951. double *locbbase;
  3952. LUdblptr ptra;  /* For converting ptr to 2D array */
  3953. ulong elapsed;
  3954. ulong j,i;              /* Indexes */
  3955.  
  3956.  
  3957. /*
  3958. ** Move the seed arrays (a & b) into the destination
  3959. ** arrays;
  3960. */
  3961. for(j=0;j<numarrays;j++)
  3962. {       locabase=abase+j*LUARRAYROWS*LUARRAYCOLS;
  3963.         locbbase=bbase+j*LUARRAYROWS;
  3964.         for(i=0;i<LUARRAYROWS*LUARRAYCOLS;i++)
  3965.                 *(locabase+i)=*(a+i);
  3966.         for(i=0;i<LUARRAYROWS;i++)
  3967.                 *(locbbase+i)=*(b+i);
  3968. }
  3969.  
  3970. /*
  3971. ** Do test...begin timing.
  3972. */
  3973. elapsed=StartStopwatch();
  3974. for(i=0;i<numarrays;i++)
  3975. {       locabase=abase+i*LUARRAYROWS*LUARRAYCOLS;
  3976.         locbbase=bbase+i*LUARRAYROWS;
  3977.         ptra.ptrs.p=locabase;
  3978.         lusolve(*ptra.ptrs.ap,LUARRAYROWS,locbbase);
  3979. }
  3980.  
  3981. return(StopStopwatch(elapsed));
  3982. }
  3983.  
  3984. /******************
  3985. ** build_problem **
  3986. *******************
  3987. ** Constructs a solvable set of linear equations.  It does this by
  3988. ** creating an identity matrix, then loading the solution vector
  3989. ** with random numbers.  After that, the identity matrix and
  3990. ** solution vector are randomly "scrambled".  Scrambling is
  3991. ** done by (a) randomly selecting a row and multiplying that
  3992. ** row by a random number and (b) adding one randomly-selected
  3993. ** row to another.
  3994. */
  3995. static void build_problem(double a[][LUARRAYCOLS],
  3996.                 int n,
  3997.                 double b[LUARRAYROWS])
  3998. {
  3999. long i,j,k,k1;  /* Indexes */
  4000. double rcon;     /* Random constant */
  4001.  
  4002. /*
  4003. ** Reset random number generator
  4004. */
  4005. randnum(13L);
  4006.  
  4007. /*
  4008. ** Build an identity matrix.
  4009. ** We'll also use this as a chance to load the solution
  4010. ** vector.
  4011. */
  4012. for(i=0;i<n;i++)
  4013. {       b[i]=(double)(abs_randwc(100L)+1L);
  4014.         for(j=0;j<n;j++)
  4015.                 if(i==j)
  4016.                         a[i][j]=(double)(abs_randwc(1000L)+1L);
  4017.                 else
  4018.                         a[i][j]=(double)0.0;
  4019. }
  4020.  
  4021. #ifdef DEBUG
  4022. for(i=0;i<n;i++)
  4023. {
  4024.         for(j=0;j<n;j++)
  4025.                 printf("%6.2f ",a[i][j]);
  4026.         printf(":: %6.2f\n",b[i]);
  4027. }
  4028. #endif
  4029.  
  4030. /*
  4031. ** Scramble.  Do this 8n times.  See comment above for
  4032. ** a description of the scrambling process.
  4033. */
  4034.  
  4035. for(i=0;i<8*n;i++)
  4036. {
  4037.         /*
  4038.         ** Pick a row and a random constant.  Multiply
  4039.         ** all elements in the row by the constant.
  4040.         */
  4041.  /*       k=abs_randwc((long)n);
  4042.         rcon=(double)(abs_randwc(20L)+1L);
  4043.         for(j=0;j<n;j++)
  4044.                 a[k][j]=a[k][j]*rcon;
  4045.         b[k]=b[k]*rcon;
  4046. */
  4047.         /*
  4048.         ** Pick two random rows and add second to
  4049.         ** first.  Note that we also occasionally multiply
  4050.         ** by minus 1 so that we get a subtraction operation.
  4051.         */
  4052.         k=abs_randwc((long)n);
  4053.         k1=abs_randwc((long)n);
  4054.         if(k!=k1)
  4055.         {
  4056.                 if(k<k1) rcon=(double)1.0;
  4057.                         else rcon=(double)-1.0;
  4058.                 for(j=0;j<n;j++)
  4059.                         a[k][j]+=a[k1][j]*rcon;;
  4060.                 b[k]+=b[k1]*rcon;
  4061.         }
  4062. }
  4063.  
  4064. return;
  4065. }
  4066.  
  4067.  
  4068. /***********
  4069. ** ludcmp **
  4070. ************
  4071. ** From the procedure of the same name in "Numerical Recipes in Pascal",
  4072. ** by Press, Flannery, Tukolsky, and Vetterling.
  4073. ** Given an nxn matrix a[], this routine replaces it by the LU
  4074. ** decomposition of a rowwise permutation of itself.  a[] and n
  4075. ** are input.  a[] is output, modified as follows:
  4076. **   --                       --
  4077. **  |  b(1,1) b(1,2) b(1,3)...  |
  4078. **  |  a(2,1) b(2,2) b(2,3)...  |
  4079. **  |  a(3,1) a(3,2) b(3,3)...  |
  4080. **  |  a(4,1) a(4,2) a(4,3)...  |
  4081. **  |  ...                      |
  4082. **   --                        --
  4083. **
  4084. ** Where the b(i,j) elements form the upper triangular matrix of the
  4085. ** LU decomposition, and the a(i,j) elements form the lower triangular
  4086. ** elements.  The LU decomposition is calculated so that we don't
  4087. ** need to store the a(i,i) elements (which would have laid along the
  4088. ** diagonal and would have all been 1).
  4089. **
  4090. ** indx[] is an output vector that records the row permutation
  4091. ** effected by the partial pivoting; d is output as +/-1 depending
  4092. ** on whether the number of row interchanges was even or odd,
  4093. ** respectively.
  4094. ** Returns 0 if matrix singular, else returns 1.
  4095. */
  4096. static int ludcmp(double a[][LUARRAYCOLS],
  4097.                 int n,
  4098.                 int indx[],
  4099.                 int *d)
  4100. {
  4101.  
  4102. double *vv;     /* Row scaling vector */
  4103. double big;     /* Holds largest element value */
  4104. double sum;
  4105. double dum;     /* Holds dummy value */
  4106. int i,j,k;      /* Indexes */
  4107. int imax;       /* Holds max index value */
  4108. double tiny;    /* A really small number */
  4109. int systemerror;
  4110.  
  4111. tiny=(double)1.0e-20;
  4112.  
  4113. /*
  4114. ** Allocate space for the scaling vector vv.
  4115. */
  4116. vv=(double *)AllocateMemory(sizeof(double)*LUARRAYROWS,&systemerror);
  4117. if(systemerror)
  4118. {       /* If we die here...it's a real mess.... */
  4119.         printf("FPU:LU -- Out of memory in ludcmp\n");
  4120.         ErrorExit();
  4121. }
  4122.  
  4123. *d=1;           /* No interchanges yet */
  4124.  
  4125. for(i=0;i<n;i++)
  4126. {       big=(double)0.0;
  4127.         for(j=0;j<n;j++)
  4128.                 if((double)fabs(a[i][j]) > big)
  4129.                         big=fabs(a[i][j]);
  4130.         /* Bail out on singular matrix */
  4131.         if(big==(double)0.0) return(0);
  4132.         vv[i]=1.0/big;
  4133. }
  4134.  
  4135. /*
  4136. ** Crout's algorithm...loop over columns.
  4137. */
  4138. for(j=0;j<n;j++)
  4139. {       if(j!=0)
  4140.                 for(i=0;i<j;i++)
  4141.                 {       sum=a[i][j];
  4142.                         if(i!=0)
  4143.                                 for(k=0;k<i;k++)
  4144.                                         sum-=(a[i][k]*a[k][j]);
  4145.                         a[i][j]=sum;
  4146.                 }
  4147.         big=(double)0.0;
  4148.         for(i=j;i<n;i++)
  4149.         {       sum=a[i][j];
  4150.                 if(j!=0)
  4151.                         for(k=0;k<j;k++)
  4152.                                 sum-=a[i][k]*a[k][j];
  4153.                 a[i][j]=sum;
  4154.                 dum=vv[i]*fabs(sum);
  4155.                 if(dum>=big)
  4156.                 {       big=dum;
  4157.                         imax=i;
  4158.                 }
  4159.         }
  4160.         if(j!=imax)             /* Interchange rows if necessary */
  4161.         {       for(k=0;k<n;k++)
  4162.                 {       dum=a[imax][k];
  4163.                         a[imax][k]=a[j][k];
  4164.                         a[j][k]=dum;
  4165.                 }
  4166.                 *d=-*d;         /* Change parity of d */
  4167.                 dum=vv[imax];
  4168.                 vv[imax]=vv[j]; /* Don't forget scale factor */
  4169.                 vv[j]=dum;
  4170.         }
  4171.         indx[j]=imax;
  4172.         /*
  4173.         ** If the pivot element is zero, the matrix is singular
  4174.         ** (at least as far as the precision of the machine
  4175.         ** is concerned.)  We'll take the original author's
  4176.         ** recommendation and replace 0.0 with "tiny".
  4177.         */
  4178.         if(a[j][j]==(double)0.0)
  4179.                 a[j][j]=tiny;
  4180.  
  4181.         if(j!=(n-1))
  4182.         {       dum=1.0/a[j][j];
  4183.                 for(i=j+1;i<n;i++)
  4184.                         a[i][j]=a[i][j]*dum;
  4185.         }
  4186. }
  4187. FreeMemory((farvoid *)vv,&systemerror);
  4188.  
  4189. return(1);
  4190. }
  4191.  
  4192. /***********
  4193. ** lubksb **
  4194. ************
  4195. ** Also from "Numerical Recipes in Pascal".
  4196. ** This routine solves the set of n linear equations A X = B.
  4197. ** Here, a[][] is input, not as the matrix A, but as its
  4198. ** LU decomposition, created by the routine ludcmp().
  4199. ** Indx[] is input as the permutation vector returned by ludcmp().
  4200. **  b[] is input as the right-hand side an returns the
  4201. ** solution vector X.
  4202. ** a[], n, and indx are not modified by this routine and
  4203. ** can be left in place for different values of b[].
  4204. ** This routine takes into account the possibility that b will
  4205. ** begin with many zero elements, so it is efficient for use in
  4206. ** matrix inversion.
  4207. */
  4208. static void lubksb( double a[][LUARRAYCOLS],
  4209.                 int n,
  4210.                 int indx[LUARRAYROWS],
  4211.                 double b[LUARRAYROWS])
  4212. {
  4213.  
  4214. int i,j;        /* Indexes */
  4215. int ip;         /* "pointer" into indx */
  4216. int ii;
  4217. double sum;
  4218.  
  4219. /*
  4220. ** When ii is set to a positive value, it will become
  4221. ** the index of the first nonvanishing element of b[].
  4222. ** We now do the forward substitution. The only wrinkle
  4223. ** is to unscramble the permutation as we go.
  4224. */
  4225. ii=-1;
  4226. for(i=0;i<n;i++)
  4227. {       ip=indx[i];
  4228.         sum=b[ip];
  4229.         b[ip]=b[i];
  4230.         if(ii!=-1)
  4231.                 for(j=ii;j<i;j++)
  4232.                         sum=sum-a[i][j]*b[j];
  4233.         else
  4234.                 /*
  4235.                 ** If a nonzero element is encountered, we have
  4236.                 ** to do the sums in the loop above.
  4237.                 */
  4238.                 if(sum!=(double)0.0)
  4239.                         ii=i;
  4240.         b[i]=sum;
  4241. }
  4242. /*
  4243. ** Do backsubstitution
  4244. */
  4245. for(i=(n-1);i>=0;i--)
  4246. {
  4247.         sum=b[i];
  4248.         if(i!=(n-1))
  4249.                 for(j=(i+1);j<n;j++)
  4250.                         sum=sum-a[i][j]*b[j];
  4251.         b[i]=sum/a[i][i];
  4252. }
  4253. return;
  4254. }
  4255.  
  4256. /************
  4257. ** lusolve **
  4258. *************
  4259. ** Solve a linear set of equations: A x = b
  4260. ** Original matrix A will be destroyed by this operation.
  4261. ** Returns 0 if matrix is singular, 1 otherwise.
  4262. */
  4263. static int lusolve(double a[][LUARRAYCOLS],
  4264.                 int n,
  4265.                 double b[LUARRAYROWS])
  4266. {
  4267. int indx[LUARRAYROWS];
  4268. int d;
  4269. #ifdef DEBUG
  4270. int i,j;
  4271. #endif
  4272.  
  4273. if(ludcmp(a,n,indx,&d)==0) return(0);
  4274.  
  4275. /* Matrix not singular -- proceed */
  4276. lubksb(a,n,indx,b);
  4277.  
  4278. #ifdef DEBUG
  4279. for(i=0;i<n;i++)
  4280. {
  4281.         for(j=0;j<n;j++)
  4282.                 printf("%6.2f ",a[i][j]);
  4283.         printf(":: %6.2f\n",b[i]);
  4284. }
  4285. #endif
  4286.  
  4287. return(1);
  4288. }
  4289.